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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions