Skip to content

disable_liga doesn't disable 'calt', so fonts like Fira Code still apply ligatures #127

Description

@SupernovaIa

Description of bug / unexpected behavior

disable_liga (passed through from manim.Text(..., disable_ligatures=True)) sets the Pango font feature string 'liga=0,dlig=0,clig=0,hlig=0' in manimpango/cmanimpango.pyx (both text2svg and text2pango), but this doesn't cover every OpenType feature fonts can use to implement ligatures.

Popular monospaced/programming fonts — Fira Code being the most common example — implement their programming ligatures (<=, ->, !=, etc.) exclusively through the calt (contextual alternates) feature, not through liga/dlig/clig/hlig. I confirmed this by inspecting Fira Code's own GSUB table with fontTools:

from fontTools.ttLib import TTFont
font = TTFont("FiraCode-Regular.ttf")
tags = {fr.FeatureTag for fr in font["GSUB"].table.FeatureList.FeatureRecord}
print(sorted(tags))
# ['aalt', 'calt', 'case', 'ccmp', 'cv01', ..., 'locl', ...]
# note: no 'liga', 'dlig', 'clig', or 'hlig' at all

So when a manim.Text/Code mobject is rendered with such a font and disable_ligatures=True, Pango still merges e.g. < and = into a single glyph via calt, silently breaking the "one glyph per character" guarantee that disable_ligatures is supposed to provide. On the manim side, this manifests as a confusing IndexError in Text._gen_chars() (see ManimCommunity/manim#3237, where several users hit this with Fira Code without understanding why, and ManimCommunity/manim#4868, where I improved that error message but couldn't fix the actual root cause since it lives here).

Expected behavior

disable_liga should also disable calt, so that character-for-glyph guarantees hold for fonts (like Fira Code) that implement their ligatures through that feature.

How to reproduce the issue

from manim import Code

Code(
    code_string="print(1<=2)",
    language="python",
    paragraph_config={"font": "Fira Code"},
)

(Requires Fira Code, or another calt-ligature font, to be installed.)

Suggested fix

In manimpango/cmanimpango.pyx, both occurrences of:

font_features='liga=0,dlig=0,clig=0,hlig=0'

would need to become:

font_features='liga=0,dlig=0,clig=0,hlig=0,calt=0'

I haven't built/tested this myself (would need to set up the Cython/C build), so I'm filing this as a diagnosis rather than a PR — happy to see if it holds up if someone with the build environment ready wants to verify it, or I may come back to it later with the toolchain set up.

System specifications

System Details
  • OS: macOS 26.5.1
  • Font tested: Fira Code (Homebrew cask font-fira-code, version 6.2)
  • Manim version: 0.20.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions