r""" Visitor for (custom glyph) MathML elements. The element is used to display non-standard symbols or images within mathematical expressions. It references external images via the 'src' attribute or font glyphs via 'fontfamily' and 'index' attributes. In LaTeX conversion, mglyph is converted to text representations or fallback Unicode characters when available. For image-based glyphs, alt text is used if provided. """ from lxml import etree as ET from ..core.interfaces import Visitor, Strategy from ..utils import local_name as _local, text_content as _text_content class MglyphVisitor(Visitor): r""" Handles (custom glyph) MathML elements. Converts custom glyphs to LaTeX text or fallback Unicode. Since LaTeX doesn't support arbitrary image references, we use alt text or text content as fallback. Examples: Glyph with alt text: → \text{custom symbol} Glyph with font reference: → \text{α} Glyph without alt (uses src filename): → \text{alpha} Glyph with width/height (ignored in LaTeX): → \text{β} Note: LaTeX doesn't support external image references in math mode, so we convert to text representations using alt attribute or derive from src filename. """ def __init__(self, strategy: Strategy): """Initialize the Mglyph visitor.""" super().__init__(strategy) def visit(self, node: ET.Element) -> str: r""" Convert element to LaTeX text. Args: node: The element to convert Returns: LaTeX string with \text{...} fallback Raises: ValueError: If node is not a element """ if not self.can_handle(node): raise ValueError(f"MglyphVisitor cannot handle element '{node.tag}'") # Try to get alt text (primary fallback) alt_text = node.get("alt", "") if alt_text: # Use alt text if provided return f"\\text{{{alt_text}}}" # Fallback: try to derive from src attribute src = node.get("src", "") if src: # Extract filename without extension as fallback import os filename = os.path.splitext(os.path.basename(src))[0] if filename: return f"\\text{{{filename}}}" # Last resort: fontfamily reference or empty fontfamily = node.get("fontfamily", "") if fontfamily: # Can't do much with font references in LaTeX return f"\\text{{{fontfamily}}}" # Completely empty - render as empty return "" def can_handle(self, node: ET.Element) -> bool: """Check if this visitor can handle the given node.""" return _local(node.tag) == 'mglyph' @property def element_name(self) -> str: """Get the element name this visitor handles.""" return 'mglyph' def __repr__(self) -> str: """String representation for debugging.""" return f"MglyphVisitor(strategy={self.strategy.name})"