icons.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. # Copyright 2020 Google LLC
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Utility to generate codepoint files for Google-style iconfonts."""
  15. from fontTools import ttLib
  16. import functools
  17. from pathlib import Path
  18. _PUA_CODEPOINTS = [
  19. range(0xE000, 0xF8FF + 1),
  20. range(0xF0000, 0xFFFFD + 1),
  21. range(0x100000, 0x10FFFD + 1)
  22. ]
  23. def _is_pua(codepoint):
  24. return any(r for r in _PUA_CODEPOINTS if codepoint in r)
  25. def _cmap(ttfont):
  26. def _cmap_reducer(acc, u):
  27. acc.update(u)
  28. return acc
  29. unicode_cmaps = (t.cmap for t in ttfont['cmap'].tables if t.isUnicode())
  30. return functools.reduce(_cmap_reducer, unicode_cmaps, {})
  31. def _LookupSubtablesOfType(lookup_list, lookup_type):
  32. # Direct matches
  33. for lookup in lookup_list.Lookup:
  34. if lookup.LookupType == lookup_type:
  35. for subtable in lookup.SubTable:
  36. yield subtable
  37. def _ligatures(ttfont):
  38. lookup_list = ttfont['GSUB'].table.LookupList
  39. # Direct ligatures
  40. for subtable in _LookupSubtablesOfType(lookup_list, 4):
  41. yield subtable.ligatures
  42. # Extensions
  43. for ext_subtable in _LookupSubtablesOfType(lookup_list, 7):
  44. if ext_subtable.ExtensionLookupType == 4:
  45. yield ext_subtable.ExtSubTable.ligatures
  46. def enumerate(font_file: Path):
  47. """Yields (icon name, codepoint) tuples for icon font."""
  48. with ttLib.TTFont(font_file) as ttfont:
  49. cmap = _cmap(ttfont)
  50. rev_cmap = {v: k for k, v in cmap.items()}
  51. for lig_root in _ligatures(ttfont):
  52. for first_glyph_name, ligatures in lig_root.items():
  53. for ligature in ligatures:
  54. glyph_names = (first_glyph_name,) + tuple(ligature.Component)
  55. icon_name = ''.join(chr(rev_cmap[n]) for n in glyph_names)
  56. codepoint = rev_cmap[ligature.LigGlyph]
  57. if not _is_pua(codepoint):
  58. continue
  59. yield (icon_name, codepoint)