# -*- mode: Perl -*-
# /=====================================================================\ #
# | xy | #
# | Implementation for LaTeXML | #
# |=====================================================================| #
# | Part of LaTeXML: | #
# | Public domain software, produced as part of work done by the | #
# | United States Government & not subject to copyright in the US. | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov> #_# | #
# | http://dlmf.nist.gov/LaTeXML/ (o o) | #
# \=========================================================ooo==U==ooo=/ #
package LaTeXML::Package::Pool;
use strict;
use warnings;
use LaTeXML::Package;
# Load the raw TeX implementation
# But IMPORTANTLY: do NOT reassign the catcode of @,
# as it fouls up all xy's catcode management!
InputDefinitions('xy', type => 'tex', noltxml => 1, at_letter => 0);
# Redefine \xyoption to avoid other drivers
Let('\lx@xy@xyoption@orig', '\xyoption');
# Prevent loading of incompatible drivers
our %xy_other_drivers = map { ($_ => 1); }
qw(16textures 17oztex dvidrv dvips dvitops oztex pdf textures dvi);
our %xy_unsupported = map { ($_ => 1); } qw(barr movie necula smart);
DefMacro('\xyoption{}', sub {
my ($gullet, $option) = @_;
$option = Tokens(Expand($option));
my $option_s = ToString($option);
if ($xy_other_drivers{$option_s}) {
Info('xy', 'ignored', $gullet, "Ignoring xy driver $option_s (using latexml)");
return; }
elsif ($xy_unsupported{$option}) {
Warn('xy', 'unsupported', $gullet,
"The xy extension/feature $option_s may not be supported"); }
my $cache_key = "loaded_xyoption_$option_s";
if (LookupValue($cache_key)) {
Info('xy', 'ignored', "xyoption $option_s was requested twice, not reloading");
return ();
} else {
Note("loading xyoption $option_s.");
AssignValue($cache_key, 1, 'global');
return Tokens(T_CS('\lx@xy@xyoption@orig'), T_BEGIN, $option, T_END); }
}, locked => 1);
# Redefine so we get more tracable/debugable info
DefPrimitive('\xywarning@{}', sub { Info('xy', 'warning', $_[0], ToString($_[1])); });
DefPrimitive('\xyerror@{}{}', sub { Info('xy', 'error', $_[0], ToString($_[1]), ToString($_[2])); });
# Is this safe for non-LaTeX ??
# We need to defer till AFTER extensions/features are loaded!
# ORR we need to implement the activate machinery!
RawTeX('\AtBeginDocument{\xyoption{latexml}}');
# ORRRRR is \activatedriver (or related) the right place to load/turn on????
######################################################################
# Cribbed from Deyan's version
# TODO: Reconsider if this is the best we can do about the XY fonts?
# At least, avoid the warning...
foreach ('dash', 'atip', 'btip', 'bsql', 'circ') {
DefPrimitiveI(
"\\xy$_" . "font", undef, undef,
font => { family => 'nullfont' },
locked => 1
);
}
# Note that xy heavily uses grouping to limit scope of image data
# and \edef to smuggle recorded data out of the groups.
# We can use the Digested parameter type here to capture a Box,
# since \xy starts with an \hbox \bgroup, and \endxy contains a matching \egroup.
# However, we have to take steps to capture the size before that group ends!
DefConstructor('\lx@xy@svgnested Digested',
"<svg:g transform='#transform'>#1</svg:g>",
properties => sub {
my ($x0, $y0, $x1, $y1) = @{ LookupValue('saved_xy_range')
|| [Dimension(0), Dimension(0), Dimension(0), Dimension(0)] };
Debug("Nested XY: " . ToString($x0) . ' ' . ToString($y0) . ' ' . ToString($x1) . ' ' . ToString($y1))
if $LaTeXML::DEBUG{xy};
my $w = $x1->subtract($x0);
my $h = $y1->subtract($y0);
my $x = $x0->larger(Dimension(0)); # negate here, not below!
my $y = Dimension(0);
if (LookupValue('IN_MATH')) { # Vertically center, when in math
$y = $y->subtract($h->multiply(0.5)); }
my $transform = "matrix(1 0 0 1 " . $x->pxValue . ' ' . $y->pxValue . ')';
return (width => $w, height => $y1, depth => $y0->negate, transform => $transform); });
DefConstructor('\lx@xy@svg Digested',
"<ltx:picture><svg:svg overflow='visible' version='1.1' width='#pxwidth' height='#pxheight'>"
. "<svg:g transform='#transform'>#1</svg:g>"
. "</svg:svg></ltx:picture>",
properties => sub {
my ($x0, $y0, $x1, $y1) = @{ LookupValue('saved_xy_range')
|| [Dimension(0), Dimension(0), Dimension(0), Dimension(0)] };
Debug("XY: " . ToString($x0) . ' ' . ToString($y0) . ' ' . ToString($x1) . ' ' . ToString($y1))
if $LaTeXML::DEBUG{xy};
my $w = $x1->subtract($x0);
my $h = $y1->subtract($y0);
my $x = $x0->negate->larger(Dimension(0));
my $yma = Dimension(LookupValue('IN_MATH') ? '2.5pt' : 0); # math-axis; fontdimen 22
my $y = $y1->add($yma->subtract($y0->larger(Dimension(0))));
my $transform = "matrix(1 0 0 -1 " . $x->pxValue . ' ' . $y->pxValue . ')';
Debug("XY size: " . ToString($w) . ' x ' . ToString($h) . ' + ' . 0 . ' @ ' . ToString($x) . ' x ' . ToString($y))
if $LaTeXML::DEBUG{xy};
return (width => $w, height => $h, pxwidth => $w->pxValue, pxheight => $h->pxValue,
transform => $transform); });
DefPrimitive('\lx@xy@capturerange', sub {
my ($stomach) = @_;
AssignValue('saved_xy_range'
=> [map { LookupRegister($_); } '\X@min', '\Y@min', '\X@max', '\Y@max'], 'global'); });
Let(T_CS('\lx@xy@original'), T_CS('\xy'));
Let(T_CS('\end@lx@xy@original'), T_CS('\endxy'));
DefMacro('\xy', '\if\inxy@\lx@xy@svgnested\else\lx@xy@svg\fi\lx@xy@original');
DefMacro('\endxy', '\relax\lx@xy@capturerange\end@lx@xy@original');
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1;