diff options
author | Rasmus Andersson <rasmus@notion.se> | 2017-09-04 06:03:17 +0300 |
---|---|---|
committer | Rasmus Andersson <rasmus@notion.se> | 2017-09-04 18:12:34 +0300 |
commit | 8234b62ab762637ef24c3398b4204a8ce8db31a7 (patch) | |
tree | 1c8df547021cdb58951630a015e4101ede46dbf1 /misc/pylib/robofab/gString.py | |
parent | 31ae014e0c827dd76696fdab7e4ca3fed9f6402b (diff) | |
download | inter-8234b62ab762637ef24c3398b4204a8ce8db31a7.tar.xz |
Speeds up font compilation by around 200%
Cython is used to compile some hot paths into native Python extensions.
These hot paths were identified through running ufocompile with the hotshot
profiler and then converting file by file to Cython, starting with the "hottest"
paths and continuing until returns were deminishing. This means that only a few
Python files were converted to Cython.
Closes #23
Closes #20 (really this time)
Diffstat (limited to 'misc/pylib/robofab/gString.py')
-rwxr-xr-x | misc/pylib/robofab/gString.py | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/misc/pylib/robofab/gString.py b/misc/pylib/robofab/gString.py new file mode 100755 index 000000000..01f319da3 --- /dev/null +++ b/misc/pylib/robofab/gString.py @@ -0,0 +1,625 @@ +"""A bunch of stuff useful for glyph name comparisons and such. + +1. A group of sorted glyph name lists that can be called directly: +2. Some tools to work with glyph names to do things like build control strings.""" + +import string + +###################################################### +# THE LISTS +###################################################### + +uppercase_plain = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AE', 'OE', 'Oslash', 'Thorn', 'Eth',] + +uppercase_accents = ['Aacute', 'Abreve', 'Acaron', 'Acircumflex', 'Adblgrave', 'Adieresis', 'Agrave', 'Amacron', 'Aogonek', 'Aring', 'Aringacute', 'Atilde', 'Bdotaccent', 'Cacute', 'Ccaron', 'Ccircumflex', 'Cdotaccent', 'Dcaron', 'Dcedilla', 'Ddotaccent', 'Eacute', 'Ebreve', 'Ecaron', 'Ecircumflex', 'Edblgrave', 'Edieresis', 'Edotaccent', 'Egrave', 'Emacron', 'Eogonek', 'Etilde', 'Fdotaccent', 'Gacute', 'Gbreve', 'Gcaron', 'Gcedilla', 'Gcircumflex', 'Gcommaaccent', 'Gdotaccent', 'Gmacron', 'Hcedilla', 'Hcircumflex', 'Hdieresis', 'Hdotaccent', 'Iacute', 'Ibreve', 'Icaron', 'Icircumflex', 'Idblgrave', 'Idieresis', 'Idieresisacute', 'Idieresisacute', 'Idotaccent', 'Igrave', 'Imacron', 'Iogonek', 'Itilde', 'Jcircumflex', 'Kacute', 'Kcaron', 'Kcedilla', 'Kcommaaccent', 'Lacute', 'Lcaron', 'Lcedilla', 'Lcommaaccent', 'Ldotaccent', 'Macute', 'Mdotaccent', 'Nacute', 'Ncaron', 'Ncedilla', 'Ncommaaccent', 'Ndotaccent', 'Ntilde', 'Oacute', 'Obreve', 'Ocaron', 'Ocircumflex', 'Odblgrave', 'Odieresis', 'Ograve', 'Ohorn', 'Ohungarumlaut', 'Omacron', 'Oogonek', 'Otilde', 'Pacute', 'Pdotaccent', 'Racute', 'Rcaron', 'Rcedilla', 'Rcommaaccent', 'Rdblgrave', 'Rdotaccent', 'Sacute', 'Scaron', 'Scedilla', 'Scircumflex', 'Scommaaccent', 'Sdotaccent', 'Tcaron', 'Tcedilla', 'Tcommaaccent', 'Tdotaccent', 'Uacute', 'Ubreve', 'Ucaron', 'Ucircumflex', 'Udblgrave', 'Udieresis', 'Udieresisacute', 'Udieresisacute', 'Udieresisgrave', 'Udieresisgrave', 'Ugrave', 'Uhorn', 'Uhungarumlaut', 'Umacron', 'Uogonek', 'Uring', 'Utilde', 'Vtilde', 'Wacute', 'Wcircumflex', 'Wdieresis', 'Wdotaccent', 'Wgrave', 'Xdieresis', 'Xdotaccent', 'Yacute', 'Ycircumflex', 'Ydieresis', 'Ydotaccent', 'Ygrave', 'Ytilde', 'Zacute', 'Zcaron', 'Zcircumflex', 'Zdotaccent', 'AEacute', 'Ccedilla', 'Oslashacute', 'Ldot'] + +uppercase_special_accents = ['Dcroat', 'Lslash', 'Hbar', 'Tbar', 'LL', 'Eng'] + +uppercase_ligatures = ['IJ'] + +uppercase = uppercase_plain+uppercase_accents+uppercase_special_accents+uppercase_ligatures + +lowercase_plain = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'dotlessi', 'dotlessj', 'ae', 'oe', 'oslash', 'thorn', 'eth', 'germandbls', 'longs',] + +lowercase_accents = ['aacute', 'abreve', 'acaron', 'acircumflex', 'adblgrave', 'adieresis', 'agrave', 'amacron', 'aogonek', 'aring', 'aringacute', 'atilde', 'bdotaccent', 'cacute', 'ccaron', 'ccircumflex', 'cdotaccent', 'dcaron', 'dcedilla', 'ddotaccent', 'dmacron', 'eacute', 'ebreve', 'ecaron', 'ecircumflex', 'edblgrave', 'edieresis', 'edotaccent', 'egrave', 'emacron', 'eogonek', 'etilde', 'fdotaccent', 'gacute', 'gbreve', 'gcaron', 'gcedilla', 'gcircumflex', 'gcommaaccent', 'gdotaccent', 'gmacron', 'hcedilla', 'hcircumflex', 'hdieresis', 'hdotaccent', 'iacute', 'ibreve', 'icaron', 'icircumflex', 'idblgrave', 'idieresis', 'idieresisacute', 'idieresisacute', 'igrave', 'imacron', 'iogonek', 'itilde', 'jcaron', 'jcircumflex', 'kacute', 'kcaron', 'kcedilla', 'kcommaaccent', 'lacute', 'lcaron', 'lcedilla', 'lcommaaccent', 'ldotaccent', 'macute', 'mdotaccent', 'nacute', 'ncaron', 'ncedilla', 'ncommaaccent', 'ndotaccent', 'ntilde', 'oacute', 'obreve', 'ocaron', 'ocircumflex', 'odblgrave', 'odieresis', 'ograve', 'ohorn', 'ohungarumlaut', 'omacron', 'oogonek', 'otilde', 'pacute', 'pdotaccent', 'racute', 'rcaron', 'rcedilla', 'rcommaaccent', 'rdblgrave', 'rdotaccent', 'sacute', 'scaron', 'scedilla', 'scircumflex', 'scommaaccent', 'sdotaccent', 'tcaron', 'tcedilla', 'tcommaaccent', 'tdieresis', 'tdotaccent', 'uacute', 'ubreve', 'ucaron', 'ucircumflex', 'udblgrave', 'udieresis', 'udieresisacute', 'udieresisacute', 'udieresisgrave', 'udieresisgrave', 'ugrave', 'uhorn', 'uhungarumlaut', 'umacron', 'uogonek', 'uring', 'utilde', 'vtilde', 'wacute', 'wcircumflex', 'wdieresis', 'wdotaccent', 'wgrave', 'wring', 'xdieresis', 'xdotaccent', 'yacute', 'ycircumflex', 'ydieresis', 'ydotaccent', 'ygrave', 'yring', 'ytilde', 'zacute', 'zcaron', 'zcircumflex', 'zdotaccent', 'aeacute', 'ccedilla', 'oslashacute', 'ldot', ] + +lowercase_special_accents = ['dcroat', 'lslash', 'hbar', 'tbar', 'kgreenlandic', 'longs', 'll', 'eng'] + +lowercase_ligatures = ['fi', 'fl', 'ff', 'ffi', 'ffl', 'ij'] + +lowercase = lowercase_plain+lowercase_accents+lowercase_special_accents+lowercase_ligatures + +smallcaps_plain = ['A.sc', 'B.sc', 'C.sc', 'D.sc', 'E.sc', 'F.sc', 'G.sc', 'H.sc', 'I.sc', 'J.sc', 'K.sc', 'L.sc', 'M.sc', 'N.sc', 'O.sc', 'P.sc', 'Q.sc', 'R.sc', 'S.sc', 'T.sc', 'U.sc', 'V.sc', 'W.sc', 'X.sc', 'Y.sc', 'Z.sc', 'AE.sc', 'OE.sc', 'Oslash.sc', 'Thorn.sc', 'Eth.sc', ] + +smallcaps_accents = ['Aacute.sc', 'Acircumflex.sc', 'Adieresis.sc', 'Agrave.sc', 'Aring.sc', 'Atilde.sc', 'Ccedilla.sc', 'Eacute.sc', 'Ecircumflex.sc', 'Edieresis.sc', 'Egrave.sc', 'Iacute.sc', 'Icircumflex.sc', 'Idieresis.sc', 'Igrave.sc', 'Ntilde.sc', 'Oacute.sc', 'Ocircumflex.sc', 'Odieresis.sc', 'Ograve.sc', 'Otilde.sc', 'Scaron.sc', 'Uacute.sc', 'Ucircumflex.sc', 'Udieresis.sc', 'Ugrave.sc', 'Yacute.sc', 'Ydieresis.sc', 'Zcaron.sc', 'Ccedilla.sc', 'Lslash.sc', ] + +smallcaps_special_accents = ['Dcroat.sc', 'Lslash.sc', 'Hbar.sc', 'Tbar.sc', 'LL.sc', 'Eng.sc'] + +smallcaps_ligatures = ['IJ.sc'] + +smallcaps = smallcaps_plain + smallcaps_accents + smallcaps_special_accents + smallcaps_ligatures + +all_accents = uppercase_accents + uppercase_special_accents + lowercase_accents +lowercase_special_accents + smallcaps_accents + smallcaps_special_accents + +digits = ['one', 'onefitted', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'zero'] + +digits_oldstyle = ['eight.oldstyle', 'five.oldstyle', 'four.oldstyle', 'nine.oldstyle', 'one.oldstyle', 'seven.oldstyle', 'six.oldstyle', 'three.oldstyle', 'two.oldstyle', 'zero.oldstyle'] + +digits_superior = ['eight.superior', 'five.superior', 'four.superior', 'nine.superior', 'one.superior', 'seven.superior', 'six.superior', 'three.superior', 'two.superior', 'zero.superior'] + +digits_inferior = ['eight.inferior', 'five.inferior', 'four.inferior', 'nine.inferior', 'one.inferior', 'seven.inferior', 'three.inferior', 'two.inferior', 'zero.inferior'] + +fractions = ['oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onequarter', 'threequarters', 'onethird', 'twothirds', 'onehalf'] + +currency = ['dollar', 'cent', 'currency', 'Euro', 'sterling', 'yen', 'florin', 'franc', 'lira'] + +currency_oldstyle = ['cent.oldstyle', 'dollar.oldstyle'] + +currency_superior = ['cent.superior', 'dollar.superior'] + +currency_inferior = ['cent.inferior', 'dollar.inferior'] + +inferior = ['eight.inferior', 'five.inferior', 'four.inferior', 'nine.inferior', 'one.inferior', 'seven.inferior', 'three.inferior', 'two.inferior', 'zero.inferior', 'cent.inferior', 'dollar.inferior', 'comma.inferior', 'hyphen.inferior', 'parenleft.inferior', 'parenright.inferior', 'period.inferior'] + +superior = ['eight.superior', 'five.superior', 'four.superior', 'nine.superior', 'one.superior', 'seven.superior', 'six.superior', 'three.superior', 'two.superior', 'zero.superior', 'cent.superior', 'dollar.superior', 'Rsmallinverted.superior', 'a.superior', 'b.superior', 'comma.superior', 'd.superior', 'equal.superior', 'e.superior', 'glottalstopreversed.superior', 'hhook.superior', 'h.superior', 'hyphen.superior', 'i.superior', 'j.superior', 'l.superior', 'm.superior', 'n.superior', 'o.superior', 'parenleft.superior', 'parenright.superior', 'period.superior', 'plus.superior', 'r.superior', 'rturned.superior', 's.superior', 't.superior', 'w.superior', 'x.superior', 'y.superior'] + +accents = ['acute', 'acutecomb', 'breve', 'caron', 'cedilla', 'circumflex', 'commaaccent', 'dblgrave', 'dieresis', 'dieresisacute', 'dieresisacute', 'dieresisgrave', 'dieresisgrave', 'dotaccent', 'grave', 'dblgrave', 'gravecomb', 'hungarumlaut', 'macron', 'ogonek', 'ring', 'ringacute', 'tilde', 'tildecomb', 'horn', 'Acute.sc', 'Breve.sc', 'Caron.sc', 'Cedilla.sc', 'Circumflex.sc', 'Dieresis.sc', 'Dotaccent.sc', 'Grave.sc', 'Hungarumlaut.sc', 'Macron.sc', 'Ogonek.sc', 'Ring.sc', 'Tilde.sc'] + +dashes = ['hyphen', 'endash', 'emdash', 'threequartersemdash', 'underscore', 'underscoredbl', 'figuredash'] + +legal = ['trademark', 'trademarksans', 'trademarkserif', 'copyright', 'copyrightsans', 'copyrightserif', 'registered', 'registersans', 'registerserif'] + +ligatures = ['fi', 'fl', 'ff', 'ffi', 'ffl', 'ij', 'IJ'] + +punctuation = ['period', 'periodcentered', 'comma', 'colon', 'semicolon', 'ellipsis', 'exclam', 'exclamdown', 'exclamdbl', 'question', 'questiondown'] + +numerical = ['percent', 'perthousand', 'infinity', 'numbersign', 'degree', 'colonmonetary', 'dotmath'] + +slashes = ['slash', 'backslash', 'bar', 'brokenbar', 'fraction'] + +special = ['ampersand', 'paragraph', 'section', 'bullet', 'dagger', 'daggerdbl', 'asterisk', 'at', 'asciicircum', 'asciitilde'] + + +dependencies = { + 'A': ['Aacute', 'Abreve', 'Acaron', 'Acircumflex', 'Adblgrave', 'Adieresis', 'Agrave', 'Amacron', 'Aogonek', 'Aring', 'Aringacute', 'Atilde'], + 'B': ['Bdotaccent'], + 'C': ['Cacute', 'Ccaron', 'Ccircumflex', 'Cdotaccent', 'Ccedilla'], + 'D': ['Dcaron', 'Dcedilla', 'Ddotaccent'], + 'E': ['Eacute', 'Ebreve', 'Ecaron', 'Ecircumflex', 'Edblgrave', 'Edieresis', 'Edotaccent', 'Egrave', 'Emacron', 'Eogonek', 'Etilde'], + 'F': ['Fdotaccent'], + 'G': ['Gacute', 'Gbreve', 'Gcaron', 'Gcedilla', 'Gcircumflex', 'Gcommaaccent', 'Gdotaccent', 'Gmacron'], + 'H': ['Hcedilla', 'Hcircumflex', 'Hdieresis', 'Hdotaccent'], + 'I': ['Iacute', 'Ibreve', 'Icaron', 'Icircumflex', 'Idblgrave', 'Idieresis', 'Idieresisacute', 'Idieresisacute', 'Idotaccent', 'Igrave', 'Imacron', 'Iogonek', 'Itilde'], + 'J': ['Jcircumflex'], + 'K': ['Kacute', 'Kcaron', 'Kcedilla', 'Kcommaaccent'], + 'L': ['Lacute', 'Lcaron', 'Lcedilla', 'Lcommaaccent', 'Ldotaccent', 'Ldot'], + 'M': ['Macute', 'Mdotaccent'], + 'N': ['Nacute', 'Ncaron', 'Ncedilla', 'Ncommaaccent', 'Ndotaccent', 'Ntilde'], + 'O': ['Oacute', 'Obreve', 'Ocaron', 'Ocircumflex', 'Odblgrave', 'Odieresis', 'Ograve', 'Ohorn', 'Ohungarumlaut', 'Omacron', 'Oogonek', 'Otilde'], + 'P': ['Pacute', 'Pdotaccent'], + 'R': ['Racute', 'Rcaron', 'Rcedilla', 'Rcommaaccent', 'Rdblgrave', 'Rdotaccent'], + 'S': ['Sacute', 'Scaron', 'Scedilla', 'Scircumflex', 'Scommaaccent', 'Sdotaccent'], + 'T': ['Tcaron', 'Tcedilla', 'Tcommaaccent', 'Tdotaccent'], + 'U': ['Uacute', 'Ubreve', 'Ucaron', 'Ucircumflex', 'Udblgrave', 'Udieresis', 'Udieresisacute', 'Udieresisacute', 'Udieresisgrave', 'Udieresisgrave', 'Ugrave', 'Uhorn', 'Uhungarumlaut', 'Umacron', 'Uogonek', 'Uring', 'Utilde'], + 'V': ['Vtilde'], + 'W': ['Wacute', 'Wcircumflex', 'Wdieresis', 'Wdotaccent', 'Wgrave'], + 'X': ['Xdieresis', 'Xdotaccent'], + 'Y': ['Yacute', 'Ycircumflex', 'Ydieresis', 'Ydotaccent', 'Ygrave', 'Ytilde'], + 'Z': ['Zacute', 'Zcaron', 'Zcircumflex', 'Zdotaccent'], + 'AE': ['AEacute'], + 'Oslash': ['Oslashacute'], + + 'a': ['aacute', 'abreve', 'acaron', 'acircumflex', 'adblgrave', 'adieresis', 'agrave', 'amacron', 'aogonek', 'aring', 'aringacute', 'atilde'], + 'b': ['bdotaccent'], + 'c': ['cacute', 'ccaron', 'ccircumflex', 'cdotaccent', 'ccedilla'], + 'd': ['dcaron', 'dcedilla', 'ddotaccent', 'dmacron'], + 'e': ['eacute', 'ebreve', 'ecaron', 'ecircumflex', 'edblgrave', 'edieresis', 'edotaccent', 'egrave', 'emacron', 'eogonek', 'etilde'], + 'f': ['fdotaccent'], + 'g': ['gacute', 'gbreve', 'gcaron', 'gcedilla', 'gcircumflex', 'gcommaaccent', 'gdotaccent', 'gmacron'], + 'h': ['hcedilla', 'hcircumflex', 'hdieresis', 'hdotaccent'], + 'i': ['iacute', 'ibreve', 'icaron', 'icircumflex', 'idblgrave', 'idieresis', 'idieresisacute', 'idieresisacute', 'igrave', 'imacron', 'iogonek', 'itilde'], + 'j': ['jcaron', 'jcircumflex'], + 'k': ['kacute', 'kcaron', 'kcedilla', 'kcommaaccent'], + 'l': ['lacute', 'lcaron', 'lcedilla', 'lcommaaccent', 'ldotaccent', 'ldot'], + 'm': ['macute', 'mdotaccent'], + 'n': ['nacute', 'ncaron', 'ncedilla', 'ncommaaccent', 'ndotaccent', 'ntilde'], + 'o': ['oacute', 'obreve', 'ocaron', 'ocircumflex', 'odblgrave', 'odieresis', 'ograve', 'ohorn', 'ohungarumlaut', 'omacron', 'oogonek', 'otilde'], + 'p': ['pacute', 'pdotaccent'], + 'r': ['racute', 'rcaron', 'rcedilla', 'rcommaaccent', 'rdblgrave', 'rdotaccent'], + 's': ['sacute', 'scaron', 'scedilla', 'scircumflex', 'scommaaccent', 'sdotaccent'], + 't': ['tcaron', 'tcedilla', 'tcommaaccent', 'tdieresis', 'tdotaccent'], + 'u': ['uacute', 'ubreve', 'ucaron', 'ucircumflex', 'udblgrave', 'udieresis', 'udieresisacute', 'udieresisacute', 'udieresisgrave', 'udieresisgrave', 'ugrave', 'uhorn', 'uhungarumlaut', 'umacron', 'uogonek', 'uring', 'utilde'], + 'v': ['vtilde'], + 'w': ['wacute', 'wcircumflex', 'wdieresis', 'wdotaccent', 'wgrave', 'wring'], + 'x': ['xdieresis', 'xdotaccent'], + 'y': ['yacute', 'ycircumflex', 'ydieresis', 'ydotaccent', 'ygrave', 'yring', 'ytilde'], + 'z': ['zacute', 'zcaron', 'zcircumflex', 'zdotaccent'], + 'ae': ['aeacute'], + 'oslash': ['oslashacute'], + } +###################################################### +# MISC TOOLS +###################################################### + +def breakSuffix(glyphname): + """ + Breaks the glyphname into a two item list + 0: glyphname + 1: suffix + + if a suffix is not found it returns None + """ + if glyphname.find('.') != -1: + split = glyphname.split('.') + return split + else: + return None + +def findAccentBase(accentglyph): + """Return the base glyph of an accented glyph + for example: Ugrave.sc returns U.sc""" + base = splitAccent(accentglyph)[0] + return base + +def splitAccent(accentglyph): + """ + Split an accented glyph into a two items + 0: base glyph + 1: accent list + + for example: Yacute.scalt45 returns: (Y.scalt45, [acute]) + and: aacutetilde.alt45 returns (a.alt45, [acute, tilde]) + """ + base = None + suffix = '' + accentList=[] + broken = breakSuffix(accentglyph) + if broken is not None: + suffix = broken[1] + base = broken[0] + else: + base=accentglyph + ogbase=base + temp_special = lowercase_special_accents + uppercase_special_accents + if base in lowercase_plain + uppercase_plain + smallcaps_plain: + pass + elif base not in temp_special: + for accent in accents: + if base.find(accent) != -1: + base = base.replace(accent, '') + accentList.append(accent) + counter={} + for accent in accentList: + counter[ogbase.find(accent)] = accent + counterList = counter.keys() + counterList.sort() + finalAccents = [] + for i in counterList: + finalAccents.append(counter[i]) + accentList = finalAccents + if len(suffix) != 0: + base = '.'.join([base, suffix]) + return base, accentList + + +###################################################### +# UPPER, LOWER, SMALL +###################################################### + +casedict = { + 'germandbls' : 'S/S', + 'dotlessi' : 'I', + 'dotlessj' : 'J', + 'ae' : 'AE', + 'aeacute' : 'AEacute', + 'oe' : 'OE', + 'll' : 'LL' + } + +casedictflip = {} + +smallcapscasedict = { + 'germandbls' : 'S.sc/S.sc', + 'question' : 'question.sc', + 'questiondown' : 'questiondown.sc', + 'exclam' : 'exclam.sc', + 'exclamdown' : 'exclamdown.sc', + 'ampersand' : 'ampersand.sc' + } + +class _InternalCaseFunctions: + """internal functions for doing gymnastics with the casedicts""" + + def expandsmallcapscasedict(self): + for i in casedict.values(): + if i not in smallcapscasedict.keys(): + if len(i) > 1: + if i[:1].upper() == i[:1]: + smallcapscasedict[i] = i[:1] + i[1:] + '.sc' + + for i in uppercase: + if i + '.sc' in smallcaps: + if i not in smallcapscasedict.keys(): + smallcapscasedict[i] = i + '.sc' + + def flipcasedict(self): + for i in casedict.keys(): + if i.find('dotless') != -1: + i = i.replace('dotless', '') + casedictflip[casedict[i]] = i + + def expandcasedict(self): + for i in lowercase_ligatures: + casedict[i] = i.upper() + for i in lowercase: + if i not in casedict.keys(): + if string.capitalize(i) in uppercase: + casedict[i] = string.capitalize(i) + + +def upper(glyphstring): + """Convert all possible characters to uppercase in a glyph string.""" + + _InternalCaseFunctions().expandcasedict() + uc = [] + for i in glyphstring.split('/'): + if i.find('.sc') != -1: + if i[-3] != '.sc': + x = i.replace('.sc', '.') + else: + x = i.replace('.sc', '') + i = x + suffix = '' + bS = breakSuffix(i) + if bS is not None: + suffix = bS[1] + i = bS[0] + if i in casedict.keys(): + i = casedict[i] + if len(suffix) != 0: + i = '.'.join([i, suffix]) + uc.append(i) + return '/'.join(uc) + +def lower(glyphstring): + """Convert all possible characters to lowercase in a glyph string.""" + + _InternalCaseFunctions().expandcasedict() + _InternalCaseFunctions().flipcasedict() + lc = [] + for i in glyphstring.split('/'): + if i.find('.sc') != -1: + if i[-3] != '.sc': + x = i.replace('.sc', '.') + else: + x = i.replace('.sc', '') + i = x + suffix = '' + bS = breakSuffix(i) + if breakSuffix(i) is not None: + suffix = bS[1] + i = bS[0] + if i in casedictflip.keys(): + i = casedictflip[i] + if len(suffix) != 0: + i = '.'.join([i, suffix]) + lc.append(i) + return '/'.join(lc) + +def small(glyphstring): + """Convert all possible characters to smallcaps in a glyph string.""" + + _InternalCaseFunctions().expandcasedict() + _InternalCaseFunctions().expandsmallcapscasedict() + sc = [] + for i in glyphstring.split('/'): + suffix = '' + bS = breakSuffix(i) + if bS is not None: + suffix = bS[1] + if suffix == 'sc': + suffix = '' + i = bS[0] + if i in lowercase: + if i not in smallcapscasedict.keys(): + i = casedict[i] + if i in smallcapscasedict.keys(): + i = smallcapscasedict[i] + if i != 'S.sc/S.sc': + if len(suffix) != 0: + if i[-3:] == '.sc': + i = ''.join([i, suffix]) + else: + i = '.'.join([i, suffix]) + sc.append(i) + return '/'.join(sc) + + +###################################################### +# CONTROL STRING TOOLS +###################################################### + + +controldict = { + 'UC' : ['/H/H', '/H/O/H/O', '/O/O'], + 'LC' : ['/n/n', '/n/o/n/o', '/o/o'], + 'SC' : ['/H.sc/H.sc', '/H.sc/O.sc/H.sc/O.sc', '/O.sc/O.sc'], + 'DIGITS' : ['/one/one', '/one/zero/one/zero', '/zero/zero'], + } + + +def controls(glyphname): + """Send this a glyph name and get a control string + with all glyphs separated by slashes.""" + controlslist = [] + for value in controldict.values(): + for v in value: + for i in v.split('/'): + if len(i) > 0: + if i not in controlslist: + controlslist.append(i) + cs = '' + if glyphname in controlslist: + for key in controldict.keys(): + for v in controldict[key]: + if glyphname in v.split('/'): + con = controldict[key] + striptriple = [] + hold1 = '' + hold2 = '' + for i in ''.join(con).split('/'): + if len(i) != 0: + if i == hold1 and i == hold2: + pass + else: + striptriple.append(i) + hold1 = hold2 + hold2 = i + constr = '/' + '/'.join(striptriple) + # this is a bit of a hack since FL seems to have trouble + # when it encounters the same string more than once. + # so, let's stick the glyph at the end to differentiate it. + # for example: HHOHOOH and HHOHOOO + cs = constr + '/' + glyphname + else: + suffix = '' + bS = breakSuffix(glyphname) + if bS is not None: + suffix = bS[1] + glyphname = bS[0] + if suffix[:2] == 'sc': + controls = controldict['SC'] + elif glyphname in uppercase: + controls = controldict['UC'] + elif glyphname in lowercase: + controls = controldict['LC'] + elif glyphname in digits: + controls = controldict['DIGITS'] + else: + controls = controldict['UC'] + if len(suffix) != 0: + glyphname = '.'.join([glyphname, suffix]) + cs = controls[0] + '/' + glyphname + controls[1] + '/' + glyphname + controls[2] + return cs + + +def sortControlList(list): + """Roughly sort a list of control strings.""" + + controls = [] + for v in controldict.values(): + for w in v: + for x in w.split('/'): + if len(x) is not None: + if x not in controls: + controls.append(x) + temp_digits = digits + digits_oldstyle + fractions + temp_currency = currency + currency_oldstyle + ss_uppercase = [] + ss_lowercase = [] + ss_smallcaps = [] + ss_digits = [] + ss_currency = [] + ss_other = [] + for i in list: + glyphs = i.split('/') + c = glyphs[2] + for glyph in glyphs: + if len(glyph) is not None: + if glyph not in controls: + c = glyph + if c in uppercase: + ss_uppercase.append(i) + elif c in lowercase: + ss_lowercase.append(i) + elif c in smallcaps: + ss_smallcaps.append(i) + elif c in temp_digits: + ss_digits.append(i) + elif c in temp_currency: + ss_currency.append(i) + else: + ss_other.append(i) + ss_uppercase.sort() + ss_lowercase.sort() + ss_smallcaps.sort() + ss_digits.sort() + ss_currency.sort() + ss_other.sort() + return ss_uppercase + ss_lowercase + ss_smallcaps + ss_digits + ss_currency + ss_other + + +# under contruction! +kerncontroldict = { + 'UC/UC' : ['/H/H', '/H/O/H/O/O'], + 'UC/LC' : ['', '/n/n/o/n/e/r/s'], + 'UC/SORTS' : ['/H/H', '/H/O/H/O/O'], + 'UC/DIGITS' : ['/H/H', '/H/O/H/O/O'], + 'LC/LC' : ['/n/n', '/n/o/n/o/o'], + 'LC/SORTS' : ['/n/n', '/n/o/n/o/o'], + 'LC/DIGITS' : ['', '/n/n/o/n/e/r/s'], + 'SC/SC' : ['/H.sc/H.sc', '/H.sc/O.sc/H.sc/O.sc/O.sc'], + 'UC/SC' : ['', '/H.sc/H.sc/O.sc/H.sc/O.sc/O.sc'], + 'SC/SORTS' : ['/H.sc/H.sc', '/H.sc/O.sc/H.sc/O.sc/O.sc'], + 'SC/DIGITS' : ['', '/H.sc/H.sc/O.sc/H.sc/O.sc/O.sc'], + 'DIGITS/DIGITS' : ['/H/H', '/H/O/H/O/O'], + 'DIGITS/SORTS' : ['/H/H', '/H/O/H/O/O'], + 'SORTS/SORTS' : ['/H/H', '/H/O/H/O/O'], + } + +def kernControls(leftglyphname, rightglyphname): + """build a control string based on the left glyph and right glyph""" + + sorts = currency + accents + dashes + legal + numerical + slashes + special + + l = leftglyphname + r = rightglyphname + lSuffix = '' + rSuffix = '' + bSL = breakSuffix(l) + if bSL is not None: + lSuffix = bSL[1] + l = bSL[0] + bSR = breakSuffix(r) + if bSR is not None: + rSuffix = bSR[1] + r = bSR[0] + if lSuffix[:2] == 'sc' or rSuffix[:2] == 'sc': + if l in uppercase or r in uppercase: + controls = kerncontroldict['UC/SC'] + elif l in digits or r in digits: + controls = kerncontroldict['SC/DIGITS'] + elif l in sorts or r in sorts: + controls = kerncontroldict['SC/SORTS'] + else: + controls = kerncontroldict['SC/SC'] + elif l in uppercase or r in uppercase: + if l in lowercase or r in lowercase: + controls = kerncontroldict['UC/LC'] + elif l in digits or r in digits: + controls = kerncontroldict['UC/DIGITS'] + elif l in sorts or r in sorts: + controls = kerncontroldict['UC/SORTS'] + else: + controls = kerncontroldict['UC/UC'] + elif l in lowercase or r in lowercase: + if l in uppercase or r in uppercase: + controls = kerncontroldict['UC/LC'] + elif l in digits or r in digits: + controls = kerncontroldict['LC/DIGITS'] + elif l in sorts or r in sorts: + controls = kerncontroldict['LC/SORTS'] + else: + controls = kerncontroldict['LC/LC'] + elif l in digits or r in digits: + if l in uppercase or r in uppercase: + controls = kerncontroldict['UC/DIGITS'] + elif l in lowercase or r in lowercase: + controls = kerncontroldict['LC/DIGITS'] + elif l in sorts or r in sorts: + controls = kerncontroldict['DIGITS/SORTS'] + else: + controls = kerncontroldict['DIGITS/DIGITS'] + elif l in sorts and r in sorts: + controls = kerncontroldict['SORTS/SORTS'] + else: + controls = kerncontroldict['UC/UC'] + + if len(lSuffix) != 0: + l = '.'.join([l, lSuffix]) + if len(rSuffix) != 0: + r = '.'.join([r, rSuffix]) + + cs = controls[0] + '/' + l + '/' + r + controls[1] + + return cs + + +###################################################### + +class _testing: + def __init__(self): + print + print '##### testing!' + # self.listtest() + # self.accentbasetest() + # self.controlstest() + self.upperlowersmalltest() + # self.stringsorttest() + + def listtest(self): + testlist = [ + uppercase, + uppercase_accents, + lowercase, + lowercase_accents, + smallcaps, + smallcaps_accents, + digits, + digits_oldstyle, + digits_superior, + digits_inferior, + fractions, + currency, + currency_oldstyle, + currency_superior, + currency_inferior, + inferior, + superior, + accents, + dashes, + legal, + ligatures, + punctuation, + numerical, + slashes, + special + ] + for i in testlist: + print i + + + def accentbasetest(self): + print findAccentBase('Adieresis') + print findAccentBase('Adieresis.sc') + print findAccentBase('Thorn.sc') + print findAccentBase('notaralglyphname') + + + def controlstest(self): + print kernControls('A', 'a.swash') + print kernControls('A.sc', '1') + print kernControls('bracket.sc', 'germandbls') + print kernControls('2', 'X') + print kernControls('Y', 'X') + print kernControls('Y.alt', 'X') + print kernControls('Y.scalt', 'X') + #print controls('x') + #print controls('germandbls') + #print controls('L') + #print controls('L.sc') + #print controls('Z.sc') + #print controls('seven') + #print controls('question') + #print controls('unknown') + + def upperlowersmalltest(self): + u = upper('/H/i/Z.sc/ampersand.sc/dotlessi/germandbls/four.superior/LL') + l = lower('/H/I/Z.sc/ampersand.sc/dotlessi/germandbls/four.superior/LL') + s = small('/H/i/Z.sc/ampersand.alt/dotlessi/germandbls/four.superior/LL') + print u + print l + print s + print lower(u) + print upper(l) + print upper(s) + print lower(s) + + def stringsorttest(self): + sample = "/H/H/Euro/H/O/H/O/Euro/O/O /H/H/R/H/O/H/O/R/O/O /H/H/question/H/O/H/O/question/O/O /H/H/sterling/H/O/H/O/sterling/O/O /n/n/r/n/o/n/o/r/o/o" + list = string.split(sample, ' ') + x = sortControlList(list) + print x + +if __name__ == '__main__': + _testing()
\ No newline at end of file |