icons.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  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 _ligatures(ttfont):
  32. liga_lookups = tuple(
  33. filter(lambda l: l.LookupType == 4,
  34. ttfont['GSUB'].table.LookupList.Lookup))
  35. for lookup in liga_lookups:
  36. for subtable in lookup.SubTable:
  37. yield subtable.ligatures
  38. def enumerate(font_file: Path):
  39. """Yields (icon name, codepoint) tuples for icon font."""
  40. with ttLib.TTFont(font_file) as ttfont:
  41. cmap = _cmap(ttfont)
  42. rev_cmap = {v: k for k, v in cmap.items()}
  43. for lig_root in _ligatures(ttfont):
  44. for first_glyph_name, ligatures in lig_root.items():
  45. for ligature in ligatures:
  46. glyph_names = (first_glyph_name,) + tuple(ligature.Component)
  47. icon_name = ''.join(chr(rev_cmap[n]) for n in glyph_names)
  48. codepoint = rev_cmap[ligature.LigGlyph]
  49. if not _is_pua(codepoint):
  50. continue
  51. yield (icon_name, codepoint)