Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions manim/mobject/text/text_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,18 @@ def font_size(self, font_val: float) -> None:
def _gen_chars(self) -> VGroup:
chars = self.get_group_class()()
submobjects_char_index = 0
non_space_chars = sum(1 for char in self.text if not char.isspace())
if non_space_chars != len(self.submobjects):
raise ValueError(
f"Text {self.original_text!r} produced {len(self.submobjects)} "
f"glyph(s) for {non_space_chars} non-space character(s) with "
"disable_ligatures=True. This usually means the chosen font "
"implements some of its ligatures through an OpenType feature "
"that isn't disabled (e.g. 'calt', used for programming "
"ligatures like '<=' or '->' by fonts such as Fira Code), so "
"characters and glyphs no longer correspond one-to-one. Try a "
"different font to work around this."
)
for char_index in range(len(self.text)):
if self.text[char_index].isspace():
space = Dot(radius=0, fill_opacity=0, stroke_opacity=0)
Expand Down
18 changes: 18 additions & 0 deletions tests/module/mobject/text/test_text_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from contextlib import redirect_stdout
from io import StringIO

import pytest

from manim.mobject.text.text_mobject import MarkupText, Text


Expand Down Expand Up @@ -32,3 +34,19 @@ def warning_printed(font: str, **kwargs) -> bool:

# check random string (should be warning)
assert warning_printed("Manim!" * 3, warn_missing_font=True)


def test_gen_chars_raises_clear_error_on_glyph_mismatch():
"""``_gen_chars`` should raise a clear, actionable error instead of an
opaque ``IndexError`` when the number of rendered glyphs doesn't match
the number of non-space characters. This happens when a font implements
some of its ligatures (e.g. programming ligatures like ``<=``) through
an OpenType feature that ``disable_ligatures`` doesn't disable, such as
``calt`` (see issue #3237). This test simulates that mismatch directly,
without depending on any particular font being installed.
"""
text = Text("ab", disable_ligatures=True)
# Simulate a font that merged "ab" into a single ligature glyph.
text.submobjects = text.submobjects[:1]
with pytest.raises(ValueError, match="glyph"):
text._gen_chars()
Loading