Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d7c0e9b
Have stomach->beginMode do leaveHorizontal, if begining a vertical or…
brucemiller Apr 23, 2026
76ace44
Add mode=internal_vertical to constructors which need it; morphing to…
brucemiller Apr 23, 2026
e8f8f0e
Have beforeDigest code directly push to LaTeXML::LIST, rather than re…
brucemiller Apr 23, 2026
be3c195
Update testcases which now better reflect correct (inline_)internal_v…
brucemiller Apr 23, 2026
2210661
T_BEGIN should only create a new List in math modes, otherwise just r…
brucemiller Apr 29, 2026
82b19d5
Make sure \hsize and friends are set consistently; update several aff…
brucemiller Apr 29, 2026
423ed3a
Make sure arg of \underline,\overline are in restricted_horizontal; a…
brucemiller Apr 29, 2026
2bae3da
Make ltx_verbatim nowrap; hack fancyvrb to use that css class
brucemiller Apr 29, 2026
251a24b
Make \lx@tag and friends compute their size
brucemiller Apr 30, 2026
daa9dbf
soul's commands should process their arg in restricted_horizontal
brucemiller Apr 30, 2026
58736fe
Make sure captions arg processed as paragraph mode (horizontal), and …
brucemiller Apr 30, 2026
1abcf81
Update tests for caption change
brucemiller Apr 30, 2026
53489cb
Extract internals of stomach->digestNextBody to stomach->digestUntil …
brucemiller Apr 30, 2026
3cc1eb9
minipage defaults to justify alignment
brucemiller May 7, 2026
8835f23
Pass context as block for svg:foreignObject to avoid bad span soup
brucemiller May 7, 2026
7ef75c2
Define methods allowing \multicolumn to REPLACE the column spec, so i…
brucemiller May 7, 2026
8fb9c8b
FIx column specifiers p,m,b to use \vbox so size computed correctly; …
brucemiller May 7, 2026
4e6ba3f
Redo p{},m{},b{} to create ltx:inline-block, so they work alongside @…
brucemiller May 13, 2026
dda21ba
Update several test cases affected by the different tabular p{} proce…
brucemiller May 13, 2026
004f732
Support passing more size releated properties to Font: pad(top|bottom…
brucemiller May 26, 2026
2b2ed28
Simplify simple underline/overline
brucemiller May 26, 2026
ab6fe78
Update deprecated
brucemiller May 26, 2026
55458d0
Add padding to items, equations
brucemiller May 26, 2026
e654a13
Let space squeeze when laying out paragraphs; more informative debugg…
brucemiller May 26, 2026
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
58 changes: 40 additions & 18 deletions lib/LaTeXML/Common/Font.pm
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ sub computeBoxesSize {
|| $STATE->lookupDefinition(T_CS('\hsize'));
$wrapwidth = $wrapwidth->valueOf if ref $wrapwidth; # Register or Dimension
$wrapwidth = $wrapwidth->valueOf if ref $wrapwidth; } # still Dimension (Register)
my $maxwidth = $wrapwidth || 0;
no warnings 'recursion';
my @boxes = grep { !(ref $_) || !$_->getProperty('isEmpty') }
grep { !(ref $_) || $_->can('getSize'); } $boxes->unlist;
Expand All @@ -659,24 +660,38 @@ sub computeBoxesSize {
&& (($box->getProperty('mode') || '') eq 'horizontal')) {
my $width = $box->getProperty('width') || $wrapwidth;
$width = $width->valueOf if ref $width;
$maxwidth = $width if $width && $width > $maxwidth;
push(@lines, $self->computeBoxesSize_lines($width,
$self->computeBoxesSize_words($box->unlist))); }
else {
my ($w, $h, $d) = $self->computeBoxesSize_box($box);
push(@lines, [$w, $h, $d]) if $w || $h || $d; } } }
else {
# Scan all boxes, collecting into "words", then (possibly) break into lines.
# Should get single line, if no $wrapwidth
my @words = $self->computeBoxesSize_words(@boxes);
@lines = $self->computeBoxesSize_lines($wrapwidth, @words); }
# ----------------------------------------------------------------------
# Now, stack up the multiple lines
my ($wd, $ht, $dp) = $self->computeBoxesSize_stack($vattach, @lines);

$wd = $maxwidth if $wd && $maxwidth; # Set to wrapwidth, unless empty.
if (my $th = $options{totalheight}) { # divie up totalheight, if requested
$th = $th->valueOf;
my $diff = $th - $ht - $dp;
if ($diff > 0) {
if ($vattach eq 'bottom') { $ht += $diff; }
elsif ($vattach eq 'middle') { $ht += $diff/2; $dp += $diff/2; }
else { $dp += $diff; } } }
Debug("Size boxes " . join(',', map { $_ . '=' . ToString($options{$_}); } sort keys %options) . "\n"
. " Boxes: " . ToString($boxes) . "\n"
. " Boxes: " . Stringify($boxes) . "\n"
. " Options:" . join(',',map { $_."=".ToString($options{$_}); } sort keys %options)
. " Sizes: " . join("\n", map { _showsize(@$_); } @lines) . "\n"
. " => " . _showsize($wd, $ht, $dp)) if $LaTeXML::DEBUG{'size-detailed'};
$wd += $options{padleft}->valueOf if $options{padleft};
$wd += $options{padright}->valueOf if $options{padright};
$ht += $options{padtop}->valueOf if $options{padtop};
$dp += $options{padbottom}->valueOf if $options{padbottom};
return (Dimension($wd), Dimension($ht), Dimension($dp)); }

# Compute (w/guards) the size of a single box
Expand Down Expand Up @@ -706,6 +721,7 @@ sub computeBoxesSize_words {
no warnings 'recursion';
my ($self, @boxes) = @_;
my @words = ();
my @word = ();
my $prevbox;
my $prevspace = 0;
my $size = int($self->getSize || DEFSIZE() || 10);
Expand All @@ -715,21 +731,22 @@ sub computeBoxesSize_words {
# Check for possible line-break points
if ((ref $box) && $box->getProperty('isBreak')) {
if ($wd || $ht || $dp || ($prevspace > 0)) {
push(@words, [$prevspace, $wd, $ht, $dp]);
$wd = $ht = $dp = 0; $prevspace = -1; }
push(@words, [$prevspace, $wd, $ht, $dp, @word]);
$wd = $ht = $dp = 0; $prevspace = -1; @word = (); }
else {
$prevspace = -1; } }
# Pernaps not "isSpace", but excluding struts, neg space, etc ???
elsif ((ref $box) && $box->getProperty('isSpace') && !$box->getProperty('isVerticalSpace')) {
if ($wd || $ht || $dp || ($prevspace < 0)) {
push(@words, [$prevspace, $wd, $ht, $dp]);
$wd = $ht = $dp = 0; $prevspace = $w; }
push(@words, [$prevspace, $wd, $ht, $dp, @word]);
$wd = $ht = $dp = 0; $prevspace = $w; @word = (); }
else {
$prevspace += $w; } }
else { # Else accumulate into "word"
$wd += $w;
$ht = max($ht, $h);
$dp = max($dp, $d);
push(@word, $box);
# Kern HACK for lists of individual Box's
if ($prevbox && (ref $prevbox eq 'LaTeXML::Core::Box') && (ref $box eq 'LaTeXML::Core::Box')) {
my $prevchar = substr($prevbox->getString || '', -1, 1);
Expand All @@ -741,28 +758,32 @@ sub computeBoxesSize_words {
$wd += $size * $kern; } }
}
$prevbox = $box; }
if ($wd || $ht || $dp || $prevspace) { # be sure to get last bit
push(@words, [$prevspace, $wd, $ht, $dp]); }
if ($wd || $ht || $dp || $prevspace || @word) { # be sure to get last bit
push(@words, [$prevspace, $wd, $ht, $dp, @word]); }
return @words; }

# do line breaking of words into lines, according to $wrapwidth (if), or explicit breaks.
sub computeBoxesSize_lines {
my ($self, $wrapwidth, @words) = @_;
my @lines = ();
my @line = ();
my $fuzz = Dimension('1pt')->valueOf;
my $squeeze = ($wrapwidth ? 0.6 : 1.0); # Let spaces shrink in paragraph mode
my ($wd, $ht, $dp) = (0, 0, 0);
foreach my $item (@words) {
my ($space, $w, $h, $d) = @$item;
my ($space, $w, $h, $d, @word) = @$item;
if ($space == -1) {
push(@lines, [$wd, $ht, $dp]) if $wd;
$wd = $w; $ht = $h; $dp = $d; }
elsif ((defined $wrapwidth) && ($wd + $space * 0.5 + $w > $wrapwidth)) {
push(@lines, [$wrapwidth || $wd, $ht, $dp]) if $wd;
$wd = $w; $ht = $h; $dp = $d; }
push(@lines, [$wd, $ht, $dp, @line]) if $wd;
$wd = $w; $ht = $h; $dp = $d; @line = @word; }
elsif ((defined $wrapwidth) && ($wd + $space * 0.5 + $w > $wrapwidth + $fuzz)) {
push(@lines, [$wd, $ht, $dp, @line]) if $wd;
$wd = $w; $ht = $h; $dp = $d; @line = @word; }
else {
$wd += $space + $w;
$wd += $space*$squeeze + $w;
$ht = max($ht, $h);
$dp = max($dp, $d); } }
push(@lines, [$wrapwidth || $wd, $ht, $dp]) if $wd || $ht || $dp;
$dp = max($dp, $d);
push(@line, @word); } }
push(@lines, [$wd, $ht, $dp, @line]) if $wd || $ht || $dp;
return @lines; }

# Sum up a stack of lines, determining w as max, and h & d according to $vattach.
Expand Down Expand Up @@ -835,8 +856,9 @@ sub math_bearing {
return $STATE->lookupDefinition($$mathbearingreg[abs($bearing)])->valueOf->spValue; }

sub _showsize {
my ($wd, $ht, $dp) = @_;
return ($wd / $UNITY) . " x " . ($ht / $UNITY) . " + " . ($dp / $UNITY); }
my ($wd, $ht, $dp, @stuff) = @_;
return ($wd / $UNITY) . " x " . ($ht / $UNITY) . " + " . ($dp / $UNITY)
. (@stuff ? ' '.join('', map { ToString($_); } @stuff) : ''); }

sub isSticky {
my ($self) = @_;
Expand Down
12 changes: 10 additions & 2 deletions lib/LaTeXML/Core/Alignment.pm
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ use LaTeXML::Common::XML;
use LaTeXML::Common::Dimension;
use LaTeXML::Core::Alignment::Template;
use List::Util qw(max sum);
use base qw(LaTeXML::Core::Whatsit);
use base qw(Exporter);
use base qw(LaTeXML::Core::Whatsit);
use base qw(Exporter);
our @EXPORT = (qw(
&ReadAlignmentTemplate &MatrixTemplate));

Expand Down Expand Up @@ -165,6 +165,14 @@ sub currentColumn {
my ($self) = @_;
return $$self{current_row} && $$self{current_row}->column($$self{current_column}); }

# Used by \multicolumn to replace the current column spec with a new one
# (the row has been cloned from the overall spec)
sub replaceColumn {
my ($self, $colspec) = @_;
$$self{current_row}->replaceColumn($$self{current_column}, $colspec)
if $$self{current_row};
return; }

sub getColumn {
my ($self, $n) = @_;
return $$self{current_row} && $$self{current_row}->column($n); }
Expand Down
9 changes: 9 additions & 0 deletions lib/LaTeXML/Core/Alignment/Template.pm
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,15 @@ sub column {
push(@{ $$self{columns} }, {%dup}); } } }
return ($n > 0 ? $$self{columns}->[$n - 1] : undef); }

# Used by \multicolumn to replace column $n spec with a new one
# (the row has been cloned from the overall spec)
sub replaceColumn {
my ($self, $n, $colspec) = @_;
my $N = scalar(@{ $$self{columns} });
if ($n <= $N) {
$$self{columns}->[$n] = $colspec; }
return; }

sub columns {
my ($self) = @_;
return @{ $$self{columns} }; }
Expand Down
32 changes: 16 additions & 16 deletions lib/LaTeXML/Core/Box.pm
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ sub Box {
$properties{height} = Dimension(0) unless defined $properties{height};
$properties{depth} = Dimension(0) unless defined $properties{depth}; }
my $state = $STATE;
my $mode = $properties{mode} || $state->lookupValue('MODE') || 'restricted_horizontal';
my $mode = $properties{mode} || $state->lookupValue('MODE') || 'restricted_horizontal';
if ($state->lookupValue('IN_MATH')) {
my $attr = (defined $string) && $state->lookupValue('math_token_attributes_' . $string);
my $usestring = ($attr && $$attr{replace}) || $string;
Expand All @@ -47,7 +47,7 @@ sub Box {
mode => $mode, ($attr ? %$attr : ()), %properties); }
else {
return LaTeXML::Core::Box->new($string, $font, $locator, $tokens,
mode => $mode, %properties); } }
mode => $mode, %properties); } }

#======================================================================
# Box Object
Expand Down Expand Up @@ -113,10 +113,10 @@ my %mode_abbrev = (

sub _stringify {
my ($self) = @_;
my $type = ref $self;
my $mode = $$self{properties}{mode};
my $type = ref $self;
my $mode = $$self{properties}{mode};
$type =~ s/^LaTeXML::Core:://;
$type .= '!'. ($mode_abbrev{$mode} || $mode) if $mode;
$type .= '!' . ($mode_abbrev{$mode} || $mode) if $mode;
return $type; }

sub stringify {
Expand Down Expand Up @@ -235,12 +235,6 @@ sub getSize {
unless (defined $$props{cwidth})
&& (defined $$props{cheight})
&& (defined $$props{cdepth});
Debug("SIZE of $self"
. "\n preassigned: " . _showsize($$props{width}, $$props{height}, $$props{depth})
. "\n calculated : " . _showsize($$props{cwidth}, $$props{cheight}, $$props{cdepth})
. "\n w/options " . join(',', map { $_ . "=" . ToString($options{$_}); } sort keys %options)
. "\n =>: " . _showsize($$props{width} || $$props{cwidth}, $$props{height} || $$props{cheight}, $$props{depth} || $$props{cdepth})
. "\n Of " . ToString($self)) if $LaTeXML::DEBUG{size};
return ($$props{width} || $$props{cwidth},
$$props{height} || $$props{cheight},
$$props{depth} || $$props{cdepth},
Expand All @@ -260,19 +254,25 @@ sub showSize {
#omg
# Fake computing the dimensions of strings (typically single chars).
# Eventually, this needs to link into real font data
our @sizing_properties = (qw(
width height depth totalheight vattach layout
padtop padbottom padleft padright));

sub computeSizeStore {
my ($self, %options) = @_;
no warnings 'recursion';
my $props = $self->getPropertiesRef;
$options{width} = $$props{width} if $$props{width};
$options{height} = $$props{height} if $$props{height};
$options{depth} = $$props{depth} if $$props{depth};
$options{vattach} = $$props{vattach} if $$props{vattach};
$options{layout} = $$props{layout} if $$props{layout};
map { $options{$_} = $$props{$_} if defined $$props{$_}; } @sizing_properties;
my ($w, $h, $d) = $self->computeSize(%options);
$$props{cwidth} = $w unless defined $$props{cwidth};
$$props{cheight} = $h unless defined $$props{cheight};
$$props{cdepth} = $d unless defined $$props{cdepth};
Debug("SIZE of $self"
. "\n preassigned: " . _showsize($$props{width}, $$props{height}, $$props{depth})
. "\n calculated : " . _showsize($$props{cwidth}, $$props{cheight}, $$props{cdepth})
. "\n w/options " . join(',', map { $_ . "=" . ToString($options{$_}); } sort keys %options)
. "\n =>: " . _showsize($$props{width} || $$props{cwidth}, $$props{height} || $$props{cheight}, $$props{depth} || $$props{cdepth})
. "\n Of " . ToString($self)) if $LaTeXML::DEBUG{size};
return; }

sub computeSize {
Expand Down
4 changes: 2 additions & 2 deletions lib/LaTeXML/Core/Definition/Constructor.pm
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ sub invoke {

LaTeXML::Core::Definition::startProfiling($profiled, 'digest') if $profiled;

my @pre = $self->executeBeforeDigest($stomach);
$self->executeBeforeDigest($stomach);

Debug('{' . $self->tracingCSName . '}') if $tracing;
# Get some info before we process arguments...
Expand Down Expand Up @@ -116,7 +116,7 @@ sub invoke {
$whatsit->setBody(@post, $stomach->digestNextBody((ref $cap ? $cap : undef))); @post = (); }
my @postpost = $self->executeAfterDigestBody($stomach, $whatsit);
LaTeXML::Core::Definition::stopProfiling($profiled, 'digest') if $profiled;
return (@pre, $whatsit, @post, @postpost); }
return ($whatsit, @post, @postpost); }

# Similar to executeAfterDigest
sub executeAfterDigestBody {
Expand Down
10 changes: 8 additions & 2 deletions lib/LaTeXML/Core/Definition/Primitive.pm
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@ sub isPrefix {
my ($self) = @_;
return $$self{isPrefix}; }

# Execute the beforeDigest functions (on $stomach),
# pushing the results (if any) directly on the the @LIST being accumulated.
# returns nothing
sub executeBeforeDigest {
my ($self, $stomach) = @_;
local $LaTeXML::Core::State::UNLOCKED = 1;
my @pre = grep { defined } @{ $$self{beforeDigest} || [] };
return (map { &$_($stomach) } @pre); }
foreach my $f (@pre) {
push(@LaTeXML::LIST, &$f($stomach)); }
return; }

sub executeAfterDigest {
my ($self, $stomach, @whatever) = @_;
Expand All @@ -57,7 +62,8 @@ sub invoke {

LaTeXML::Core::Definition::startProfiling($profiled, 'digest') if $profiled;
Debug('{' . $self->tracingCSName . '}') if $tracing;
my @result = ($self->executeBeforeDigest($stomach));
$self->executeBeforeDigest($stomach);
my @result = ();
my $parms = $$self{parameters};
my @args = ($parms ? $parms->readArguments($stomach->getGullet, $self) : ());
Debug($self->tracingArgs(@args)) if $tracing && @args;
Expand Down
Loading
Loading