_text_helpers.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. """
  2. Low-level text helper utilities.
  3. """
  4. import dataclasses
  5. from . import _api
  6. from .ft2font import KERNING_DEFAULT, LOAD_NO_HINTING
  7. LayoutItem = dataclasses.make_dataclass(
  8. "LayoutItem", ["ft_object", "char", "glyph_idx", "x", "prev_kern"])
  9. def warn_on_missing_glyph(codepoint):
  10. _api.warn_external(
  11. "Glyph {} ({}) missing from current font.".format(
  12. codepoint,
  13. chr(codepoint).encode("ascii", "namereplace").decode("ascii")))
  14. block = ("Hebrew" if 0x0590 <= codepoint <= 0x05ff else
  15. "Arabic" if 0x0600 <= codepoint <= 0x06ff else
  16. "Devanagari" if 0x0900 <= codepoint <= 0x097f else
  17. "Bengali" if 0x0980 <= codepoint <= 0x09ff else
  18. "Gurmukhi" if 0x0a00 <= codepoint <= 0x0a7f else
  19. "Gujarati" if 0x0a80 <= codepoint <= 0x0aff else
  20. "Oriya" if 0x0b00 <= codepoint <= 0x0b7f else
  21. "Tamil" if 0x0b80 <= codepoint <= 0x0bff else
  22. "Telugu" if 0x0c00 <= codepoint <= 0x0c7f else
  23. "Kannada" if 0x0c80 <= codepoint <= 0x0cff else
  24. "Malayalam" if 0x0d00 <= codepoint <= 0x0d7f else
  25. "Sinhala" if 0x0d80 <= codepoint <= 0x0dff else
  26. None)
  27. if block:
  28. _api.warn_external(
  29. f"Matplotlib currently does not support {block} natively.")
  30. def layout(string, font, *, kern_mode=KERNING_DEFAULT):
  31. """
  32. Render *string* with *font*. For each character in *string*, yield a
  33. (glyph-index, x-position) pair. When such a pair is yielded, the font's
  34. glyph is set to the corresponding character.
  35. Parameters
  36. ----------
  37. string : str
  38. The string to be rendered.
  39. font : FT2Font
  40. The font.
  41. kern_mode : int
  42. A FreeType kerning mode.
  43. Yields
  44. ------
  45. glyph_index : int
  46. x_position : float
  47. """
  48. x = 0
  49. prev_glyph_idx = None
  50. char_to_font = font._get_fontmap(string)
  51. base_font = font
  52. for char in string:
  53. # This has done the fallback logic
  54. font = char_to_font.get(char, base_font)
  55. glyph_idx = font.get_char_index(ord(char))
  56. kern = (
  57. base_font.get_kerning(prev_glyph_idx, glyph_idx, kern_mode) / 64
  58. if prev_glyph_idx is not None else 0.
  59. )
  60. x += kern
  61. glyph = font.load_glyph(glyph_idx, flags=LOAD_NO_HINTING)
  62. yield LayoutItem(font, char, glyph_idx, x, kern)
  63. x += glyph.linearHoriAdvance / 65536
  64. prev_glyph_idx = glyph_idx