From ec9cb8365c9d96799c1afd9dd79058c96df97380 Mon Sep 17 00:00:00 2001 From: bruce miller Date: Thu, 14 Dec 2023 13:16:48 -0500 Subject: [PATCH] More empty/spacing fixes (#2262) * Rename \@@eat@space to \lx@column@trimright to avoid confusion (it's NOT a LaTeX name), and to only trim explicit spaces, not spacing commands * Let space take up space when sizing alignment cells * IsEmpty should NOT count spaces as empty; define new IsEmptyOrSpace in case that's actually needed * Avoid some confusions about space vs empty * Update changed tests * Removed tentative general IsEmptyOrSpace since any practical usecase has peculiar, specific needs * Whatsit property the_box (typically one of the arguments) stands in for the content when checking emptiness and related tests * Define \lx@intercol as analog for LaTeX's \@acol; manage and record spacing added around alignment columns * Distinguish empty vs spacing alignment cells; Careful about pruning Alignment rows/columns that contain spaces if bordered; prepare for CSS padding to deal with spacing * Update test cases for careful alignment pruning * Add to tabular test case for rows & columns that should not be pruned * Dont prematurely strip empty boxes from alignment; repair regression in test cases * Recognize alignment cell padding (\lx@intercol) and record * Update test cases for better handling of cell padding * Disabling intercolumn spacing is more a general Template thing, than a specific column * Record all alignment cell leading/trailing space as potential padding; use to determine css; simplify \lx@intercol and its usage * Update CSS for alignment cell padding control * Update tabbing for alignment padding * Update test cases for better padding control * Make grouping commands { and } be alignment skippable so we detect spacing within groups * Don't prematurely increment cell with by l/rpadding; do account for vertical size of l/rpadding * Fix typo * Fix tests again for latest tweaks * Rename the_body to content_box --- lib/LaTeXML/Core/Alignment.pm | 152 ++++++++--- lib/LaTeXML/Core/Alignment/Template.pm | 38 ++- lib/LaTeXML/Package.pm | 15 +- lib/LaTeXML/Package/LaTeX.pool.ltxml | 17 +- lib/LaTeXML/Package/TeX.pool.ltxml | 122 ++++++--- lib/LaTeXML/Package/siunitx.sty.ltxml | 2 +- lib/LaTeXML/resources/CSS/LaTeXML.css | 15 ++ t/alignment/array.xml | 4 +- t/alignment/cells.xml | 130 +++++----- t/alignment/halign.xml | 332 ++++++++++++------------- t/alignment/halignatt.xml | 20 +- t/alignment/supertabular.xml | 96 +++---- t/alignment/tabular.pdf | Bin 12188 -> 19865 bytes t/alignment/tabular.tex | 7 + t/alignment/tabular.xml | 39 ++- t/babel/numprints.xml | 16 +- t/encoding/ly1.xml | 2 +- t/graphics/graphrot.xml | 8 +- t/graphics/picture.xml | 66 ++--- t/graphics/xcolors.xml | 78 +++--- t/structure/glossary.xml | 3 +- 21 files changed, 694 insertions(+), 468 deletions(-) diff --git a/lib/LaTeXML/Core/Alignment.pm b/lib/LaTeXML/Core/Alignment.pm index 54b05bca18..6b6458bf53 100644 --- a/lib/LaTeXML/Core/Alignment.pm +++ b/lib/LaTeXML/Core/Alignment.pm @@ -204,7 +204,6 @@ sub getColumnAfter { my ($self) = @_; my $column; if (($column = $self->currentColumn) && !$$column{omitted}) { - # Possible \@@eat@space ??? (if LaTeX style???) return Tokens(@{ $$column{after} }, T_CS('\@column@after')); } else { return Tokens(); } } @@ -329,7 +328,23 @@ sub beAbsorbed { # Normalize the border attribute my $border = join(' ', sort(map { split(/ */, $_) } $$cell{border} || '')); $border =~ s/(.) \1/$1$1/g; - my $empty = $$cell{empty} || !$$cell{boxes} || !scalar($$cell{boxes}->unlist); + my @classes = ($$cell{class}); + my $empty = $$cell{empty}; + my ($pre, $post); + # Heuristic: use common td CSS padding, or none, or explicit spacing within cell + # Ideally, we'd compare to a current \(tab|array)colsep + # and create a special CSS class for non-standard values + my $lpad = ($$cell{lspaces} ? $$cell{lspaces}->getWidth->valueOf : 0); + my $rpad = ($$cell{rspaces} ? $$cell{rspaces}->getWidth->valueOf : 0); + if ((!$empty || $$cell{boxes}) && ($lpad < Dimension('0.2em')->valueOf)) { + push(@classes, 'ltx_nopad_l') unless $ismath; } + elsif ($lpad < Dimension('1.5em')->valueOf) { } # do nothing + else { $pre = $$cell{lspaces}; } + if ((!$empty || $$cell{boxes}) && ($rpad < Dimension('0.2em')->valueOf)) { + push(@classes, 'ltx_nopad_r') unless $ismath; } + elsif ($rpad < Dimension('1.5em')->valueOf) { } # do nothing + else { $post = $$cell{rspaces}; } + my $class = join(' ', grep { $_; } @classes); $$cell{cell} = &{ $$self{openColumn} }($document, align => $$cell{align}, width => $$cell{width}, vattach => $$cell{vattach}, @@ -341,11 +356,14 @@ sub beAbsorbed { # Which properties do we expose to the constructor? x => $$cell{x}, y => $$cell{y}, cwidth => $$cell{cwidth}, cheight => $$cell{cheight}, cdepth => $$cell{cdepth}, + class => $class ); - if (!$empty) { + if (!$$cell{skippable}) { local $LaTeXML::BOX = $$cell{boxes}; $document->openElement('ltx:XMArg', rule => 'Anything,') if $ismath; # Hacky! + $document->absorb($pre) if $pre; $document->absorb($$cell{boxes}); + $document->absorb($post) if $post; $document->closeElement('ltx:XMArg') if $ismath; } &{ $$self{closeColumn} }($document); } @@ -406,33 +424,88 @@ sub normalize_cell_sizes { my ($self) = @_; # Examines: boxes, align, vattach # Sets: cwidth, cheight, cdepth (per cell) & empty + my $i = -1; foreach my $row (@{ $$self{rows} }) { + my $j = -1; + $i++; # Do we need to account for any space in the $$row{before} or $$row{after}? foreach my $cell (@{ $$row{columns} }) { + $j++; if (my $boxes = $$cell{boxes}) { my ($w, $h, $d, $cw, $ch, $cd) = $boxes->getSize(align => $$cell{align}, width => $$cell{width}, vattach => $$cell{vattach}); - Debug("CELL (" . join(',', map { $_ . "=" . ToString($$cell{$_}); } qw(align width vattach)) - . ") size " . showSize($w, $h, $d) - . " csize " . showSize($cw, $ch, $cd) - . " Boxes=" . ToString($boxes)) if $LaTeXML::DEBUG{halign} && $LaTeXML::DEBUG{size}; + my $fullw = $cw; + my ($lpad, $rpad, $padh, $padd); + if (my $lspaces = $$cell{lspaces}) { + ($lpad, $padh, $padd) = $lspaces->getSize; + $fullw = ($fullw ? $fullw->add($lpad) : $lpad) if $lpad; + $h = ($h ? $h->larger($padh) : $padh) if $padh; + $d = ($d ? $d->larger($padd) : $padd) if $padd; } + if (my $rspaces = $$cell{rspaces}) { + ($rpad, $padh, $padd) = $rspaces->getSize; + $fullw = ($fullw ? $fullw->add($rpad) : $rpad) if $rpad; + $h = ($h ? $h->larger($padh) : $padh) if $padh; + $d = ($d ? $d->larger($padd) : $padd) if $padd; } + my @boxes = $boxes->unlist; + my $isrule = scalar(@boxes) + && !(grep { !($_->getProperty('isHorizontalRule') || $_->getProperty('isVerticalRule') + || $_->getProperty('alignmentSkippable') + || (ref $_ eq 'LaTeXML::Core::Comment') + ); } @boxes); my $empty = - (((!$cw) || $cw->valueOf < 1) + (((!$fullw) || $fullw->valueOf < 1) && (((!$ch) || $ch->valueOf < 1) && ((!$cd) || $cd->valueOf < 1)) - || !(grep { !($_->getProperty('isSpace') || $_->getProperty('isHorizontalRule') || $_->getProperty('isVerticalRule')); } $boxes->unlist) + || $isrule ) && !preservedBoxes($boxes); - $$cell{cwidth} = $w || Dimension(0); - $$cell{cheight} = $h || Dimension(0); - $$cell{cdepth} = $d || Dimension(0); - $$cell{empty} = $empty; - $$cell{align} = undef if $empty; } + $$cell{cwidth} = $w || Dimension(0); + $$cell{cheight} = $h || Dimension(0); + $$cell{cdepth} = $d || Dimension(0); + $$cell{lpadding} = $lpad; + $$cell{rpadding} = $rpad; + $$cell{empty} = $empty; + $$cell{skippable} = $empty || isSkippable($boxes); + $$cell{align} = undef if $$cell{skippable}; + Debug("CELL[$i,$j] size=" . showSize($w, $h, $d) . " csize " . showSize($cw, $ch, $cd) + . ";\n " . join(',', map { $_ . "=" . ToString($$cell{$_}); } sort keys %$cell) + . "\n Boxes=" . Stringify($boxes) + ) if $LaTeXML::DEBUG{alignment_normalize}; + } else { - $$cell{empty} = 1; } + $$cell{empty} = 1; + $$cell{skippable} = 1; } } } return; } +# Check whether all these things are "empty" or only spaces or otherwise skippable in a table cell +# Very similar to IsEmpty, but also recognizes spaces or alignmentSkippable items +sub isSkippable { + my (@things) = @_; + foreach my $thing (@things) { + my $ref = ref $thing; + if (!$thing) { } + elsif ($ref eq 'LaTeXML::Core::Comment') { } + elsif ($ref eq 'LaTeXML::Core::Tokens') { + return 0 unless isSkippable($thing->unlist); } + elsif ($ref eq 'LaTeXML::Core::Token') { + my $cc = $$thing[1]; + return 0 if ($cc == CC_LETTER) || ($cc == CC_OTHER) || ($cc == CC_ACTIVE) || ($cc == CC_CS); } + elsif ((!$thing->getProperty('isEmpty')) + && (!$thing->getProperty('isSpace')) + && (!$thing->getProperty('alignmentSkippable'))) { + if ($ref eq 'LaTeXML::Core::Box') { + my $s = $thing->getString; + return 0 if (defined $s) && ($s !~ /^\s*$/); } + elsif ($ref eq 'LaTeXML::Core::List') { + return 0 unless isSkippable($thing->unlist); } + elsif ($ref eq 'LaTeXML::Core::Whatsit') { + if (my $body = $thing->getProperty('content_box')) { + return 0 unless isSkippable($body); } + else { + return 0; } } } } + return 1; } + sub showSize { my ($w, $h, $d) = @_; return '[' . ToString($w) . ' x ' . ToString($h) . ' + ' . ToString($d) . ']'; } @@ -535,7 +608,7 @@ sub normalize_sum_sizes { elsif ($a eq 'right') { $colx = $colx->add($dx); } } $$cell{x} = $colx; $$cell{y} = $rowpos[$i]; - Debug("CELL[$j,$i] " . showSize($$cell{cwidth}, $$cell{cheight}, $$cell{cdepth}) + Debug("CELL[$i,$j] " . showSize($$cell{cwidth}, $$cell{cheight}, $$cell{cdepth}) . " @ " . ToString($$cell{x}) . "," . ToString($$cell{y}) . " w/ " . join(',', map { $_ . '=' . ToString($$cell{$_}); } (qw(align vattach skipped colspan rowspan)))) @@ -580,7 +653,7 @@ sub normalize_mark_spans { if ($rrow) { for (my $jj = $j ; $jj < $j + $ncspan ; $jj++) { if (my $ccol = $$rrow{columns}[$jj]) { - if (!$$ccol{empty}) { + if (!$$ccol{skippable}) { $rowempty = 0; } } } } if (!$nrc) { } elsif (!$rrow || !$rowempty) { @@ -618,12 +691,26 @@ sub normalize_prune_rows { my @rows = @{ $$self{rows} }; my @filtered = (); for (my $i = 0 ; $i < scalar(@rows) ; $i++) { - my $row = $rows[$i]; - if (grep { !$$_{empty} } @{ $$row{columns} }) { # Not empty! so keep it + my $row = $rows[$i]; + my $next = $rows[$i + 1]; + # prunable if all cells are empty + # OR are only spacing NOT made visible by requiring both top & bottom borders + my $prunable = 1; + my $check_bracketting; + foreach my $c (@{ $$row{columns} }) { # Check if all cells are either empty or space only + $check_bracketting = 1 if $$c{skippable} && !$$c{empty}; + $prunable = 0 unless $$c{skippable}; } + if ($prunable && $check_bracketting # If spaces, make sure not bracketted by borders + && scalar(grep { ($$_{border} || '') =~ /t/i } @{ $$row{columns} })) { + if ($next) { + $prunable = 0 if scalar(grep { ($$_{border} || '') =~ /t/i } @{ $$next{columns} }); } + else { + $prunable = 0 if scalar(grep { ($$_{border} || '') =~ /b/i } @{ $$row{columns} }); } } + if (!$prunable) { push(@filtered, $row); } - elsif (my $next = $rows[$i + 1]) { # Remove empty row, but copy top border to NEXT row + elsif ($next) { # Remove empty row, but copy top border to NEXT row if ($preserve) { - push(@filtered, $row); next; } # don't remove inner rows from math EXCEPT last row!! + push(@filtered, $row); next; } # don't remove inner rows from math EXCEPT last row!! my $nc = scalar(@{ $$row{columns} }); my ($pruneh, $pruned) = (0, 0); for (my $j = 0 ; $j < $nc ; $j++) { @@ -638,7 +725,9 @@ sub normalize_prune_rows { $border =~ s/B/T/g; # but convert to top $$next{columns}[$j]{border} .= $border; } # add to NEXT row # This tpadding should be combined w/any extra rowspacing from \\[dim] ! - $$next{tpadding} = Dimension($pruneh + $pruned) if $pruneh + $pruned; } # And save padding. + $$next{tpadding} = Dimension($pruneh + $pruned) if $pruneh + $pruned; # And save padding. + Debug("PRUNE ROW $i") if $LaTeXML::DEBUG{alignment_normalize}; + } else { # Remove empty last row, but copy top border to bottom of prev. my $prev = $filtered[-1]; my $nc = scalar(@{ $$row{columns} }); @@ -657,7 +746,8 @@ sub normalize_prune_rows { if (defined $$ccol{rowspanned}) { # skip to spanning column if rowspanned! $ccol = $rows[$$ccol{rowspanned}]{columns}[$j]; } $$ccol{border} .= $border; } # add to PREVIOUS row. - $$prev{bpadding} = Dimension($pruneh + $pruned) if $pruneh + $pruned; } # And save padding. + $$prev{bpadding} = Dimension($pruneh + $pruned) if $pruneh + $pruned; # And save padding. + Debug("PRUNE ROW (last) $i") if $LaTeXML::DEBUG{alignment_normalize}; } } @rows = @filtered; $$self{rows} = [@filtered]; @@ -686,10 +776,13 @@ sub normalize_prune_columns { my $prev = $$row{columns}[$j - 1]; if (my $jj = $$prev{colspanned}) { $prev = $$row{columns}[$jj]; } - $border =~ s/[^rRlL]//g; # mask all but left border - $border =~ s/l/r/g; # convert to right - $border =~ s/L/R/g; # convert to right + $border =~ s/[^rRlL]//g; # mask all but left border + $border =~ s/l/r/g; # convert to right + $border =~ s/L/R/g; # convert to right $$prev{border} .= $border; + # Copy left spacing to right column, as well + $$prev{rspaces} = LaTeXML::Core::List::List($$prev{rspaces} || (), $$col{lspaces} || ()) if $$col{lspaces}; + $$prev{rpadding} = $$prev{rspaces}->getWidth if $$prev{rspaces}; if (my @preserve = preservedBoxes($$col{boxes})) { # Copy boxes over, in case side effects? $$prev{boxes} = LaTeXML::Core::List($$prev{boxes} ? ($$prev{boxes}->unlist, @preserve) : @preserve); } @@ -705,14 +798,16 @@ sub normalize_prune_columns { } # Now, remove the column $$row{columns} = [grep { $_ ne $col } @{ $$row{columns} }]; } } + $prunew = Dimension($prunew); if ($j) { # If not 1st row, add right padding to previous column foreach my $row (@rows) { if (my $col = $$row{columns}[$j - 1]) { - $$col{rpadding} = Dimension($prunew); } } } + $$col{rpadding} = ($$col{rpadding} ? $$col{rpadding}->add($prunew) : $prunew); } } } else { # Else add left padding to (newly) first column foreach my $row (@rows) { # And add the padding to previous column if (my $col = $$row{columns}[0]) { - $$col{lpadding} = Dimension($prunew); } } } + $$col{lpadding} = ($$col{lpadding} ? $$col{lpadding}->add($prunew) : $prunew); } } } + Debug("PRUNE COLUMN $j") if $LaTeXML::DEBUG{alignment_normalize}; } } } return; } @@ -769,6 +864,7 @@ sub ReadAlignmentTemplate { last unless $nopens; } push(@tokens, T_END); $LaTeXML::BUILD_TEMPLATE->setReversion(@tokens); + $LaTeXML::BUILD_TEMPLATE->finish; return $LaTeXML::BUILD_TEMPLATE; } sub parseAlignmentTemplate { diff --git a/lib/LaTeXML/Core/Alignment/Template.pm b/lib/LaTeXML/Core/Alignment/Template.pm index a828b29caf..16cd7d8895 100644 --- a/lib/LaTeXML/Core/Alignment/Template.pm +++ b/lib/LaTeXML/Core/Alignment/Template.pm @@ -53,11 +53,11 @@ sub addBeforeColumn { unshift(@{ $$self{save_before} }, @tokens); # NOTE: goes all the way to front! return; } -# NOTE: \@@eat@space should ONLY be added to LaTeX tabular style templates!!!! +# NOTE: \lx@column@trimright should ONLY be added to LaTeX tabular style templates!!!! # NOT \halign style templates! sub addAfterColumn { my ($self, @tokens) = @_; - $$self{current_column}{after} = Tokens(T_CS('\@@eat@space'), + $$self{current_column}{after} = Tokens(T_CS('\lx@column@trimright'), @tokens, @{ $$self{current_column}{after} }); return; } @@ -65,25 +65,38 @@ sub addAfterColumn { sub addBetweenColumn { my ($self, @tokens) = @_; my @cols = @{ $$self{columns} }; - if ($$self{current_column}) { + if (my $col = $$self{current_column}) { + if (!$$self{disabled_intercolumn}) { + unshift(@tokens, T_CS('\lx@intercol')); } $$self{current_column}{after} = Tokens(@{ $$self{current_column}{after} }, @tokens); } else { push(@{ $$self{save_between} }, @tokens); } return; } +sub disableIntercolumn { + my ($self) = @_; + if (my $col = $$self{current_column}) { + $$self{disabled_intercolumn} = 1; } + return; } + sub addColumn { my ($self, %properties) = @_; - my $col = {%properties}; + my $col = {%properties}; + if (my $prev = $$self{current_column}) { + $$prev{after} = Tokens(($$prev{after} || ()), T_CS('\lx@intercol')) + unless $$self{disabled_intercolumn}; } my @before = (); - push(@before, @{ $$self{save_between} }) if $$self{save_between}; + push(@before, @{ $$self{save_between} }) if $$self{save_between}; + push(@before, T_CS('\lx@intercol')) unless $$self{disabled_intercolumn}; + delete $$self{disabled_intercolumn}; + push(@before, $properties{before}->unlist) if $properties{before}; push(@before, @{ $$self{save_before} }) if $$self{save_before}; $$col{before} = Tokens(@before); my @after = (); - push(@after, T_CS('\@@eat@space')); + push(@after, T_CS('\lx@column@trimright')); push(@after, $properties{after}->unlist) if $properties{after}; - $$col{after} = Tokens(@after); -### $$col{after} = Tokens() unless $properties{after}; + $$col{after} = Tokens(@after); $$col{thead} = $properties{thead}; $$col{empty} = 1; $$self{save_between} = []; @@ -97,6 +110,13 @@ sub addColumn { push(@{ $$self{columns} }, $col); } return; } +sub finish { + my ($self) = @_; + if (my $prev = $$self{current_column}) { + $$prev{after} = Tokens(($$prev{after} || ()), T_CS('\lx@intercol')) + unless $$self{disabled_intercolumn}; } + return; } + # Methods for using a template. sub clone { my ($self) = @_; @@ -104,7 +124,7 @@ sub clone { foreach my $cell (@{ $$self{columns} }) { push(@dup, {%$cell}); } return bless { columns => [@dup], - repeated => $$self{repeated}, non_repeating => $$self{non_repeating}, + repeated => $$self{repeated}, non_repeating => $$self{non_repeating}, repeating => $$self{repeating} }, ref $self; } sub show { diff --git a/lib/LaTeXML/Package.pm b/lib/LaTeXML/Package.pm index 8d36279b09..d7a00a5f1d 100644 --- a/lib/LaTeXML/Package.pm +++ b/lib/LaTeXML/Package.pm @@ -974,9 +974,8 @@ sub TokenizeInternal { local $STATE = $STY_CATTABLE; return LaTeXML::Core::Mouth->new($string)->readTokens; } -# Check whether all these things are "empty" (spaces are empty!!) +# Check whether all these things are "empty" (spaces are NOT empty!!) # short-circuit: return 0 quickly if anything is NOT empty. -# Will we need to distinguish between "empty" and "not visible"?? sub IsEmpty { my (@things) = @_; foreach my $thing (@things) { @@ -988,16 +987,18 @@ sub IsEmpty { elsif ($ref eq 'LaTeXML::Core::Token') { my $cc = $$thing[1]; return 0 if ($cc == CC_LETTER) || ($cc == CC_OTHER) || ($cc == CC_ACTIVE) || ($cc == CC_CS); } - elsif ((!$thing->getProperty('isEmpty')) - && (!$thing->getProperty('isSpace'))) { # A space-like thing + elsif (!$thing->getProperty('isEmpty')) { if ($ref eq 'LaTeXML::Core::Box') { my $s = $thing->getString; - return 0 if (defined $s) && ($s !~ /^\s*$/); } + return 0 if (defined $s) && length($s); } elsif ($ref eq 'LaTeXML::Core::List') { return 0 unless IsEmpty($thing->unlist); } elsif ($ref eq 'LaTeXML::Core::Whatsit') { - return 0 unless ($thing->getDefinition eq $STATE->lookupDefinition(T_BEGIN)) - && IsEmpty($thing->getBody->unlist); } } } + # Sneaky Whatsit property for something (an arg) that stands-in for the whatsit's content. + if (my $body = $thing->getProperty('content_box')) { + return 0 unless IsEmpty($body); } + else { + return 0; } } } } return 1; } #====================================================================== diff --git a/lib/LaTeXML/Package/LaTeX.pool.ltxml b/lib/LaTeXML/Package/LaTeX.pool.ltxml index 5b21235ab8..94438288a8 100644 --- a/lib/LaTeXML/Package/LaTeX.pool.ltxml +++ b/lib/LaTeXML/Package/LaTeX.pool.ltxml @@ -2422,6 +2422,7 @@ sub eqnarrayBindings { properties => { preserve_structure => 1, attributes => {%attributes} })); Let("\\\\", '\@alignment@newline'); + Let('\lx@intercol', '\lx@math@intercol'); Let('\@row@before', '\eqnarray@row@before'); Let('\@row@after', '\eqnarray@row@after'); Let('\lx@eqnarray@save@label', '\label'); @@ -3647,11 +3648,14 @@ DefMacroI('\@tabbing@nexttab', undef, '\@tabbing@nexttab@marker&'); DefMacro('\@tabbing@newline OptionalMatch:* [Dimension]', '\@tabbing@newline@marker\cr'); DefMacroI('\@tabbing@kill', undef, '\@tabbing@kill@marker\cr\@tabbing@start@tabs'); -DefConstructorI('\@tabbing@tabset@marker', undef, '', reversion => '\='); -DefConstructorI('\@tabbing@nexttab@marker', undef, '', reversion => '\>'); +DefConstructorI('\@tabbing@tabset@marker', undef, '', reversion => '\=', + properties => { alignmentSkippable => 1 }); +DefConstructorI('\@tabbing@nexttab@marker', undef, '', reversion => '\>', + properties => { alignmentSkippable => 1 }); DefConstructorI('\@tabbing@newline@marker', undef, '', reversion => Tokens(T_CS("\\\\"), T_CR)); DefConstructorI('\@tabbing@kill@marker', undef, '', reversion => '\kill', - afterDigest => sub { LookupValue('Alignment')->removeRow; return; }); + afterDigest => sub { LookupValue('Alignment')->removeRow; return; }, + properties => { alignmentSkippable => 1 }); AssignValue(tabbing_start_tabs => Tokens()); DefMacroI('\@tabbing@start@tabs', undef, sub { LookupValue('tabbing_start_tabs')->unlist; }); @@ -3681,7 +3685,8 @@ DefMacro('\@tabbing@accent{}', sub { T_CS('\@tabbing@' . ToString($_[1])); }); sub tabbingBindings { AssignValue(Alignment => LaTeXML::Core::Alignment->new( template => LaTeXML::Core::Alignment::Template->new( - repeated => [{ after => Tokens(T_CS('\hfil')) }]), + repeated => [{ before => Tokens(T_CS('\lx@text@intercol')), + after => Tokens(T_CS('\hfil'), T_CS('\lx@text@intercol')) }]), openContainer => sub { $_[0]->openElement('ltx:tabular', @_[1 .. $#_]); }, closeContainer => sub { $_[0]->closeElement('ltx:tabular'); }, openRow => sub { $_[0]->openElement('ltx:tr', @_[1 .. $#_]); }, @@ -3757,6 +3762,7 @@ sub tabularBindings { $properties{strut} = LookupRegister('\baselineskip')->multiply(1.5); } # Account for html space alignmentBindings($template, 'text', %properties); Let("\\\\", '\@tabularcr'); + Let('\lx@intercol', '\lx@text@intercol'); Let('\tabularnewline', "\\\\"); # NOTE: Fit this back in!!!!!!! # # Do like AddToMacro, but NOT global! @@ -3873,7 +3879,8 @@ DefPrimitive('\@array@bindings [] AlignmentTemplate', sub { $$attr{rowsep} = Dimension(($str - 1) . 'em'); } alignmentBindings($template, 'math', attributes => $attr); MergeFont(mathstyle => 'text'); - Let("\\\\", '\@alignment@newline'); + Let("\\\\", '\@alignment@newline'); + Let('\lx@intercol', '\lx@math@intercol'); return; }); DefMacro('\array[]{}', diff --git a/lib/LaTeXML/Package/TeX.pool.ltxml b/lib/LaTeXML/Package/TeX.pool.ltxml index c0fbe5a98e..218a86e87b 100644 --- a/lib/LaTeXML/Package/TeX.pool.ltxml +++ b/lib/LaTeXML/Package/TeX.pool.ltxml @@ -2017,9 +2017,9 @@ DefParameterType('BoxSpecification', sub { reversion => sub { my ($spec) = @_; if (my $to = $spec && $spec->getValue('to')) { - return Tokens(Tokenize('to'), T_SPACE, Revert($to)); } + return Tokens(Tokenize('to'), Revert($to)); } elsif (my $spread = $spec && $spec->getValue('spread')) { - return Tokens(Tokenize('spread'), T_SPACE, Revert($spread)); } + return Tokens(Tokenize('spread'), Revert($spread)); } else { return; } }, optional => 1, undigested => 1); @@ -2202,6 +2202,7 @@ DefConstructor('\hbox BoxSpecification HBoxContents', sub { $whatsit->setWidth($w); } elsif (my $s = GetKeyVal($spec, 'spread')) { $whatsit->setWidth($box->getWidth->add($s)); } + $whatsit->setProperty(content_box => $box); return; }); # Cleanup foreignObjects: remove empty (or only

); and determine size @@ -2345,6 +2346,7 @@ DefConstructor('\vbox BoxSpecification VBoxContents', sub { $whatsit->setHeight($h); } elsif (my $s = GetKeyVal($spec, 'spread')) { $whatsit->setHeight($box->getHeight->add($s)); } + $whatsit->setProperty(content_box => $box); return; }); DefConstructor('\vtop BoxSpecification VBoxContents', sub { @@ -2361,6 +2363,7 @@ DefConstructor('\vtop BoxSpecification VBoxContents', sub { $whatsit->setHeight($h); } elsif (my $s = GetKeyVal($spec, 'spread')) { $whatsit->setHeight($box->getHeight->add($s)); } + $whatsit->setProperty(content_box => $box); return; }); DefParameterType('RuleSpecification', sub { @@ -2450,7 +2453,7 @@ DefConstructor('\hrule RuleSpecification', DefPrimitive('{', sub { my ($stomach) = @_; $stomach->bgroup; - my $open = Box(undef, undef, undef, T_BEGIN, isEmpty => 1); + my $open = Box(undef, undef, undef, T_BEGIN, isEmpty => 1, alignmentSkippable => 1); my $ismath = $STATE->lookupValue('IN_MATH'); my @body = $stomach->digestNextBody(); List($open, @body, mode => ($ismath ? 'math' : 'text')); }); @@ -2458,7 +2461,7 @@ DefPrimitive('{', sub { DefPrimitive('}', sub { my $f = LookupValue('font'); $_[0]->egroup; - Box(undef, $f, undef, T_END, isEmpty => 1); }); + Box(undef, $f, undef, T_END, isEmpty => 1, alignmentSkippable => 1); }); # These are for those screwy cases where you need to create a group like box, # more than just bgroup, egroup, @@ -2831,7 +2834,10 @@ DefColumnType('*{Number}{}', sub { DefColumnType('@{}', sub { my ($gullet, $filler) = @_; - $LaTeXML::BUILD_TEMPLATE->addBetweenColumn($filler->unlist); return; }); + $LaTeXML::BUILD_TEMPLATE->disableIntercolumn; + $LaTeXML::BUILD_TEMPLATE->addBetweenColumn($filler->unlist); + $LaTeXML::BUILD_TEMPLATE->disableIntercolumn; + return; }); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Alignment code @@ -2965,6 +2971,29 @@ DefConstructor('\@alignment@newline@markertall {Dimension}', '', DefMacroI('\tabularnewline', undef, '\cr'); # ??? +# \lx@intercol is our replacement for LaTeX's \@acol which places intercolumn space in tabular +# (but NOT used by TeX's \halign!) +DefMacro('\lx@intercol', ''); +# Candidates for binding \lx@intercol for LaTeX tabular or math arrays +# These provide "padding" of half tabcolsep, since added before & after columns +# [these could be \hskip\tabcolsep, but the expansion confounds trimColumnSpec] +DefConstructor('\lx@text@intercol', sub { + my ($document, %props) = @_; + $document->absorb(DimensionToSpaces($props{width})); }, + reversion => '\lx@intercol', + properties => sub { + my $defn; + my $w = (($defn = $STATE->lookupDefinition(T_CS('\tabcolsep'))) && $defn->isRegister + ? $defn->valueOf : Dimension(0)); + (width => $w, isSpace => 1); }); +DefConstructor('\lx@math@intercol', "", # mspace ??? + reversion => '\lx@intercol', + properties => sub { + my $defn; + my $w = (($defn = $STATE->lookupDefinition(T_CS('\arraycolsep'))) && $defn->isRegister + ? $defn->valueOf : Dimension(0)); + (width => $w, isSpace => 1); }); + #====================================================================== # Various decorations within alignments, rules, headers, etc @@ -3093,25 +3122,29 @@ sub translateAttachment { $pos = ($pos ? ToString($pos) : ''); return ($pos eq 't' ? 'top' : ($pos eq 'b' ? 'bottom' : 'middle')); } # undef meaning 'baseline' -# This removes trailing whitespace from the current digested list. -# It is useful as the 1st thing in the rhs template of things like {tabular}. +# This trims trailing whitespace from the current digested list, +# for use within latex tabular-style columns. # But note that \halign does NOT remove this trailing space! -DefPrimitiveI('\@@eat@space', undef, sub { +DefPrimitiveI('\lx@column@trimright', undef, sub { my $box; my @save = (); + my $s; while ($box = $LaTeXML::LIST[-1]) { if ($box->getProperty('alignmentSkippable') - || $box->getProperty('isFill')) { + || $box->getProperty('isFill') + || IsEmpty($box)) { push(@save, pop(@LaTeXML::LIST)); } - elsif (IsEmpty($box)) { - pop(@LaTeXML::LIST); } + elsif (ref $box eq 'LaTeXML::Core::List') { # Unwrap and continue + pop(@LaTeXML::LIST); + push(@LaTeXML::LIST, $box->unlist); } + elsif ((ref $box eq 'LaTeXML::Core::Box') + && defined($s = $box->getString) && ($s =~ /^\s*$/)) { + pop(@LaTeXML::LIST); } # remove any box containing only spaces else { last; } } push(@LaTeXML::LIST, @save); return; }); -#DefMacroI('\@@eat@space',undef,undef); - use constant T_hfil => T_CS('\hfil'); # Yet more special case hacking. Sometimes the order of tokens works for # TeX, but confuses us... In particular the order of $ and \hfil! @@ -3180,22 +3213,22 @@ sub parseHAlignTemplate { my ($gullet, $whatsit) = @_; my $t = $gullet->readNonSpace; Error('expected', '\bgroup', $gullet, "Missing \\halign box") unless $t->defined_as(T_BEGIN); - my $before = 1; # true if we're before a # in current column - my @pre = (); - my @post = (); - my @cols = (); - my $repeated = 0; - my @nonreps = (); - my $tabskip; # Need to use this somehow! - my @tokens = (); + my $before = 1; # true if we're before a # in current column + my @pre = (); + my @post = (); + my @cols = (); + my $repeated = 0; + my @nonreps = (); + my $tabskip = LookupRegister('\tabskip'); + my $nexttabskip = $tabskip; + my @tokens = (); ## Only expand certain things; See TeX book p.238 local $LaTeXML::ALIGN_STATE = 1000000; while ($t = $gullet->readToken) { my $cc = $t->getCatcode; if ($t->equals(T_CS('\tabskip'))) { # Read the tabskip assignment $gullet->readKeyword('='); - $tabskip = $gullet->readGlue; - push(@tokens, $t, $tabskip); } + $nexttabskip = $gullet->readGlue; } elsif ($t->equals(T_CS('\span'))) { # ex-span-ded next token. $gullet->unread($gullet->readXToken(0)); } elsif ($cc == CC_PARAM) { # Found the template's column slot @@ -3209,9 +3242,11 @@ sub parseHAlignTemplate { else { # Finished column spec; add it ## How should we be handling tabskip? An attribute on the cell or spacing? push(@cols, { - before => Tokens(beforeCellUnlist(Tokens(@pre))), - after => Tokens(afterCellUnlist(Tokens(@post))) }); - @pre = @post = (); $before = 1; } + tabskip => $tabskip, + before => Tokens(beforeCellUnlist(Tokens(@pre))), + after => Tokens(afterCellUnlist(Tokens(@post))) }); + $tabskip = $nexttabskip; + @pre = @post = (); $before = 1; } last unless $cc == CC_ALIGN; push(@tokens, $t); } elsif ($before) { # Other random tokens go into the column's pre-template @@ -3461,6 +3496,9 @@ sub extractAlignmentColumn { my @boxes = $boxes->unlist; my @saveleft = (); my @saveright = (); + my (@lspaces, @rspaces); + if (my $skip = $$colspec{tabskip}) { + push(@lspaces, Digest(Tokens(T_CS('\hskip'), $skip->revert, T_CS('\relax')))); } while (@boxes) { if (ref $boxes[0] eq 'LaTeXML::Core::List') { unshift(@boxes, shift(@boxes)->unlist); } @@ -3470,12 +3508,15 @@ sub extractAlignmentColumn { last; } elsif ($boxes[0]->getProperty('isVerticalRule')) { $border .= 'l'; + if (my $prev = $alignment->getColumn($n0 - 1)) { # space before | ? move to previous column + $$prev{rspaces} = List(($$prev{rspaces} || ()), @lspaces) if @lspaces; } + @lspaces = (); # then discard shift(@boxes); } + elsif ($boxes[0]->getProperty('isSpace')) { + push(@lspaces, shift(@boxes)); } elsif ($boxes[0]->getProperty('isHorizontalRule') || $boxes[0]->getProperty('alignmentSkippable') - || (ref $boxes[0] eq 'LaTeXML::Core::Comment') - || $boxes[0]->getProperty('isSpace') - || IsEmpty($boxes[0])) { + || (ref $boxes[0] eq 'LaTeXML::Core::Comment')) { push(@saveleft, shift(@boxes)); } else { last; } } @@ -3488,12 +3529,13 @@ sub extractAlignmentColumn { last; } elsif ($boxes[-1]->getProperty('isVerticalRule')) { $border .= 'r'; + @rspaces = (); # discard spacing after rule!!! (should save for next column?) pop(@boxes); } + elsif ($boxes[-1]->getProperty('isSpace')) { + unshift(@rspaces, pop(@boxes)); } elsif ($boxes[-1]->getProperty('isHorizontalRule') || $boxes[-1]->getProperty('alignmentSkippable') - || (ref $boxes[-1] eq 'LaTeXML::Core::Comment') - || $boxes[-1]->getProperty('isSpace') - || IsEmpty($boxes[-1])) { + || (ref $boxes[-1] eq 'LaTeXML::Core::Comment')) { unshift(@saveright, pop(@boxes)); } else { last; } } @@ -3505,7 +3547,10 @@ sub extractAlignmentColumn { $$colspec{align} = $align; $$colspec{border} = $border = ($$colspec{border} || '') . $border; $$colspec{boxes} = $boxes; + $$colspec{lspaces} = List(@lspaces) if @lspaces; + $$colspec{rspaces} = List(@rspaces) if @rspaces; $$colspec{colspan} = $n1 - $n0 + 1; + if ($$alignment{in_tabular_head} || $$alignment{in_tabular_foot}) { $$colspec{thead}{column} = 1; } for (my $i = $n0 + 1 ; $i <= $n1 ; $i++) { @@ -4360,6 +4405,7 @@ sub scriptHandler { # Parsing is too late! while (my $prev = pop(@LaTeXML::LIST)) { if (($prev->getProperty('isSpace')) + || ($prev->getProperty('isEmpty')) # EXPLICITLY empty, rather than {} || (ref $prev eq 'LaTeXML::Core::Comment')) { $prevspace = 1; # a space avoids double-scripts unshift(@putback, $prev); # put back? assuming it will add rpadding to previous??? @@ -6014,14 +6060,14 @@ DefMathI('\biguplus', undef, "\x{2A04}", # versus \x{228e} mathstyle => \&doVariablesizeOp); DefConstructorI('\limits', undef, '', afterDigest => sub { mergeLimits('mid'); }, - properties => { isSpace => 1 }); + properties => { isEmpty => 1 }); DefConstructorI('\nolimits', undef, '', afterDigest => sub { mergeLimits('post'); }, - properties => { isSpace => 1 }); + properties => { isEmpty => 1 }); DefConstructorI('\displaylimits', undef, '', afterDigest => sub { mergeLimits((($_[1]->getProperty('mathstyle') || '') eq 'display' ? 'mid' : 'post')); }, - properties => { isSpace => 1 }); + properties => { isEmpty => 1 }); sub mergeLimits { my ($pos) = @_; @@ -6765,6 +6811,7 @@ DefPrimitive('\lx@gen@matrix@bindings RequiredKeyVals:lx@GEN', sub { 'math', (keys %attributes ? (attributes => {%attributes}) : ())); # }); Let("\\\\", '\@alignment@newline'); + Let('\lx@intercol', '\lx@math@intercol'); Let('\@row@before', '\@empty'); # Disable special row treatment (eg. numbering) unless requested Let('\@row@after', '\@empty'); }); @@ -6889,11 +6936,12 @@ DefPrimitive('\lx@gen@cases@bindings RequiredKeyVals:lx@GEN', sub { { before => Tokens($style), after => Tokens(T_CS('\hfil')) }, { before => Tokens($style, ($condtext ? (T_CS('\lx@cases@condition')) : ())), - after => Tokens(T_CS('\@@eat@space'), + after => Tokens(T_CS('\lx@column@trimright'), ($condtext ? (T_CS('\lx@cases@end@condition')) : ()), T_CS('\hfil')) }]), 'math'); - Let("\\\\", '\@alignment@newline'); + Let("\\\\", '\@alignment@newline'); + Let('\lx@intercol', '\lx@math@intercol'); DefMacro('\@row@before', ''); # Don't inherit counter stepping from containing environments DefMacro('\@row@after', ''); }); diff --git a/lib/LaTeXML/Package/siunitx.sty.ltxml b/lib/LaTeXML/Package/siunitx.sty.ltxml index 1891f62cf2..e239690cf6 100644 --- a/lib/LaTeXML/Package/siunitx.sty.ltxml +++ b/lib/LaTeXML/Package/siunitx.sty.ltxml @@ -1466,7 +1466,7 @@ DefMacro('\lx@si@column@parse XUntil:\lx@si@column@end', sub { push(@pre, T_BEGIN, $p, T_END); } else { last; } } - pop(@tokens) if @tokens && Equals($tokens[-1], T_CS('\@@eat@space')); + pop(@tokens) if @tokens && Equals($tokens[-1], T_CS('\lx@column@trimright')); if (my $defns = six_convertUnits(Tokens(@tokens))) { $result = six_format_units(six_parse_units($defns)); } else { diff --git a/lib/LaTeXML/resources/CSS/LaTeXML.css b/lib/LaTeXML/resources/CSS/LaTeXML.css index 96e72f8b08..32dd24474e 100644 --- a/lib/LaTeXML/resources/CSS/LaTeXML.css +++ b/lib/LaTeXML/resources/CSS/LaTeXML.css @@ -358,6 +358,21 @@ span.ltx_rowspan { position:absolute; top:0; bottom:0; } .ltx_tabular .ltx_td, .ltx_tabular .ltx_th { padding:0.1em 0.5em; } +.ltx_tabular .ltx_td.ltx_nopad_l, +.ltx_tabular .ltx_th.ltx_nopad_l { padding-left:0; } +.ltx_tabular .ltx_td.ltx_nopad_r, +.ltx_tabular .ltx_th.ltx_nopad_r { padding-right:0; } + +/* min-height does NOT apply to tr! */ +.ltx_tabular .ltx_tr td:first-child::after, +.ltx_tabular .ltx_tr th:first-child::after { + content: ""; + display: inline-block; + vertical-align: top; + min-height: 1em; +} + + /* regular lines */ .ltx_border_t { border-top:1px solid black; } .ltx_border_r { border-right:1px solid black; } diff --git a/t/alignment/array.xml b/t/alignment/array.xml index 30fa034c84..3f915b98b8 100644 --- a/t/alignment/array.xml +++ b/t/alignment/array.xml @@ -46,11 +46,11 @@ - a – + a   – b - c – + c   – d diff --git a/t/alignment/cells.xml b/t/alignment/cells.xml index 8e4b4b06b8..6b581a685c 100644 --- a/t/alignment/cells.xml +++ b/t/alignment/cells.xml @@ -25,32 +25,32 @@ - Multilined + Multilined - cell text + cell text - + 28–31 - Left aligned + Left aligned - cell text + cell text - + 37–43 - Right aligned + Right aligned - cell text + cell text 37–43 @@ -58,18 +58,18 @@ - Bottom aligned + Bottom aligned - cell text + cell text - + 52–58 -

Cell long text with predefined width

+

Cell long text with predefined width

52–58 @@ -77,7 +77,7 @@ -

Cell long…

+

Cell long…

52–58 @@ -98,20 +98,20 @@ - First column head + First column head - + - Second + Second - multlined + multlined - column head + column head - + @@ -136,23 +136,23 @@ - First column head + First column head - + - +

-

Second multilined

+

Second multilined

-

column head

+

column head

- + @@ -209,64 +209,64 @@ - First … + First … - + - Multicolumn head + Multicolumn head - + - Second … + Second … - + - Third … + Third … - + Cell text A - 28–31 + 28–31 - + - Multilined + Multilined - Cell text + Cell text - + B - Left … + Left … - + C - 37–43 + 37–43 - + - Right … + Right … D @@ -274,23 +274,23 @@ - Bottom … + Bottom … - + E - 37–43 + 37–43 - 52–58 + 52–58 -

Cell …

+

Cell …

F @@ -298,7 +298,7 @@ -

Cell …

+

Cell …

G @@ -317,12 +317,20 @@ - 1 - 2 - 3 - 4 - 5 - 6 + + + + + + + + + 1 + 2 + 3 + 4 + 5 + 6 @@ -383,20 +391,20 @@ - Second + Second - column + column - + - Third + Third - column + column - + diff --git a/t/alignment/halign.xml b/t/alignment/halign.xml index 4a1e313a0f..5857ba1392 100644 --- a/t/alignment/halign.xml +++ b/t/alignment/halign.xml @@ -14,18 +14,18 @@ - [a] - (b) - {c} + [a] + (b) + {c} - [a] - (b) - {c} + [a] + (b) + {c} @@ -39,9 +39,9 @@ - [a] - (b) - {c} + [a] + (b) + {c} @@ -56,29 +56,29 @@ - [a] - (b) - {c} + [a] + (b) +       {c} - [a] - (b) - {c} - [d] + [a] + (b) +                               {c} +                               [d] - [a] - (b) - {c} - [d] + [a] + (b) +                               {c} +                               [d] @@ -93,60 +93,60 @@ - [a] - (b) - {c} + [a] + (b) + {c} - [a] - (b) - {c} - {a} - {b} - {c} + [a] + (b) + {c} + {a} + {b} + {c} - [a] - (b) - {c} - {a} - {b} - {c} - {a} - {b} - {c} - {b} - {c} + [a] + (b) + {c} + {a} + {b} + {c} + {a} + {b} + {c} + {b} + {c} - [a] - (b) - {c} + [a] + (b) + {c} - [a] - (b) - {c} - [a] - (b) - {c} + [a] + (b) + {c} + [a] + (b) + {c} - [a] - (b) - {c} - [a] - (b) - {c} - [a] - (b) - {c} - [b] - (c) + [a] + (b) + {c} + [a] + (b) + {c} + [a] + (b) + {c} + [b] + (c) @@ -169,74 +169,74 @@ - [a] - [b] - [c] + [a] + [b] + [c] - [d] - [e] - [f] + [d] + [e] + [f] - [] + [] - [a] + [a] - [a] - [] + [a] + [] - [a] - [b] + [a] + [b] - [a] - [b] - [] + [a] + [b] + [] - [a] - [b] - [c] + [a] + [b] + [c] - [] - [] + [] + [] - [] - [] - [] + [] + [] + [] - [a] - [b] - [c] + [a] + [b] + [c] - [] + [] - [a] - [b] - [c] + [a] + [b] + [c] - [e] - [f] - [g] + [e] + [f] + [g] @@ -251,29 +251,29 @@ - [a] - (b) - {c} + [a] + (b) + {c} - a - (b) - {c} + a + (b) + {c} - a - b - {c} + a + b + {c} - [a] - b - c + [a] + b + c - [a] - (b) - {c} + [a] + (b) + {c} @@ -288,25 +288,25 @@ - [a] - (b) - {c} + [a] + (b) + {c} - [a](b) - {c} + [a](b) + {c} - [a] - (b){c} + [a] + (b){c} - [a](b){c} + [a](b){c} - [a] - (b) - {c} + [a] + (b) + {c} @@ -321,22 +321,22 @@ - [a] - (b) - {c} + [a] + (b) + {c} - [a] - c + [a] + c - [a] - c + [a] + c - [a] - (b) - {c} + [a] + (b) + {c} @@ -351,49 +351,49 @@ - [a] - [b] + [a] + [b] - X + X - [a] - [b ] + [a] + [b ] - Y + Y - Z + Z - [a] - [b ] + [a] + [b ] - [a] - [b] + [a] + [b] - [c] - [d] + [c] + [d] - [a] - [b] + [a] + [b] - [c] - [d] + [c] + [d] @@ -409,21 +409,21 @@ - [a] - [b] + [a] + [b] - [ + [ - (a) - (b) + (a) + (b) ] - [ + [ - {a} - {b} + {a} + {b} ] @@ -441,28 +441,28 @@ - [a] - [[b]] - [c] + [a] + [[b]] + [c] - [d] - [[e]] - [f] + [d] + [[e]] + [f] - [a] - [[b]] - [c] + [a] + [[b]] + [c] - [d] - [[e]] - [f] + [d] + [[e]] + [f] diff --git a/t/alignment/halignatt.xml b/t/alignment/halignatt.xml index 5f0ffee8be..41296325bb 100644 --- a/t/alignment/halignatt.xml +++ b/t/alignment/halignatt.xml @@ -7,53 +7,53 @@ - - AT&T Common Stock + + AT&T Common Stock - + Year Price Dividend - + 1971 41–54 $2.60 - + 2 41–54 2.70 - + 3 46–55 2.87 - + 4 40–53 3.24 - + 5 45–52 3.40 - + 6 51–59 .95* - * (first quarter only) + * (first quarter only) diff --git a/t/alignment/supertabular.xml b/t/alignment/supertabular.xml index 4967a52e96..afd5ae0e03 100644 --- a/t/alignment/supertabular.xml +++ b/t/alignment/supertabular.xml @@ -71,46 +71,46 @@ - Entity - Unicode Name - Unicode +       Entity +       Unicode Name +       Unicode - alpha - GREEK SMALL LETTER ALPHA - 03B1 +       alpha +       GREEK SMALL LETTER ALPHA +       03B1 - beta - GREEK SMALL LETTER BETA - 03B2 +       beta +       GREEK SMALL LETTER BETA +       03B2 - chi - GREEK SMALL LETTER CHI - 03C7 +       chi +       GREEK SMALL LETTER CHI +       03C7 - Delta - GREEK CAPITAL LETTER DELTA - 0394 +       Delta +       GREEK CAPITAL LETTER DELTA +       0394 - delta - GREEK SMALL LETTER DELTA - 03B4 +       delta +       GREEK SMALL LETTER DELTA +       03B4 - epsi - GREEK SMALL LETTER EPSILON - 03B5 +       epsi +       GREEK SMALL LETTER EPSILON +       03B5 - epsis - GREEK LUNATE EPSILON SYMBOL - 03F5 +       epsis +       GREEK LUNATE EPSILON SYMBOL +       03F5 @@ -174,46 +174,46 @@ - Entity - Unicode Name - Unicode +       Entity +       Unicode Name +       Unicode - alpha - GREEK SMALL LETTER ALPHA - 03B1 +       alpha +       GREEK SMALL LETTER ALPHA +       03B1 - beta - GREEK SMALL LETTER BETA - 03B2 +       beta +       GREEK SMALL LETTER BETA +       03B2 - chi - GREEK SMALL LETTER CHI - 03C7 +       chi +       GREEK SMALL LETTER CHI +       03C7 - Delta - GREEK CAPITAL LETTER DELTA - 0394 +       Delta +       GREEK CAPITAL LETTER DELTA +       0394 - delta - GREEK SMALL LETTER DELTA - 03B4 +       delta +       GREEK SMALL LETTER DELTA +       03B4 - epsi - GREEK SMALL LETTER EPSILON - 03B5 +       epsi +       GREEK SMALL LETTER EPSILON +       03B5 - epsis - GREEK LUNATE EPSILON SYMBOL - 03F5 +       epsis +       GREEK LUNATE EPSILON SYMBOL +       03F5 diff --git a/t/alignment/tabular.pdf b/t/alignment/tabular.pdf index e82e818f3bf94f4786c96b7803026928f4127f2a..e745d6f5fb4b4e7bfa23043267a13fa2365f3d2a 100644 GIT binary patch literal 19865 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 literal 12188 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 Wi3{wnGJ`+@ARbIcMi~`Z%>M&)d)y=d diff --git a/t/alignment/tabular.tex b/t/alignment/tabular.tex index abd477a015..9749c3ab7d 100644 --- a/t/alignment/tabular.tex +++ b/t/alignment/tabular.tex @@ -14,4 +14,11 @@ 72 & 245 & 245 & Light trading due to a heavy winter. \\ \hline 73 & 245 & 2001 & No gnus was very good gnus this year. \\ \hline \end{tabular} + +\begin{tabular}{|c|c|c|}\hline +x&&x\\\hline +&&\\\hline +x&&x\\\hline +\end{tabular} + \end{document} diff --git a/t/alignment/tabular.xml b/t/alignment/tabular.xml index 2383a478ab..aa6e7ff84e 100644 --- a/t/alignment/tabular.xml +++ b/t/alignment/tabular.xml @@ -17,31 +17,54 @@ Year - low - high + low + high Comments 1971 - 97– - 245 + 97– + 245

Bad year.

72 - 245– - 245 + 245– + 245

Light trading due to a heavy winter.

73 - 245– - 2001 + 245– + 2001

No gnus was very good gnus this year.

+ + + + + x + + x + + + + + + + + + + x + + x + + + + diff --git a/t/babel/numprints.xml b/t/babel/numprints.xml index 2eb182059d..0e02b7fb63 100644 --- a/t/babel/numprints.xml +++ b/t/babel/numprints.xml @@ -600,7 +600,7 @@ vs. - + 123.45e12 @@ -625,7 +625,7 @@ vs. - + 123.45e12 @@ -654,7 +654,7 @@ vs. - + 123.45e12 @@ -683,10 +683,10 @@ vs. - 123.45×1012 + 123.45×1012
- + 12345.678e123 @@ -722,7 +722,7 @@ vs. - + 12345.678e123 @@ -762,7 +762,7 @@ vs. - + 12345.678e123 @@ -802,7 +802,7 @@ vs. - 12,345.678×10123 + 12,345.678×10123
diff --git a/t/encoding/ly1.xml b/t/encoding/ly1.xml index f886839621..f0279442da 100644 --- a/t/encoding/ly1.xml +++ b/t/encoding/ly1.xml @@ -72,7 +72,7 @@ ´4x - + ! " # diff --git a/t/graphics/graphrot.xml b/t/graphics/graphrot.xml index 5748a2ddbf..c42e84d0c7 100644 --- a/t/graphics/graphrot.xml +++ b/t/graphics/graphrot.xml @@ -75,7 +75,7 @@ 2 Table 2 - + @@ -122,7 +122,7 @@ 3 Table 3 - + @@ -169,7 +169,7 @@ 4 Table 4 - + @@ -448,7 +448,7 @@ the whales Save the whale Save the + Table 5 Table 5 diff --git a/t/graphics/picture.xml b/t/graphics/picture.xml index 98ab7fe47d..c609ecf8b6 100644 --- a/t/graphics/picture.xml +++ b/t/graphics/picture.xml @@ -1100,8 +1100,8 @@ square. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -336,7 +336,7 @@ A=100*13 = 1300pt;

- + @@ -344,7 +344,7 @@ A=100*13 = 1300pt;

- + @@ -352,7 +352,7 @@ A=100*13 = 1300pt;

- + @@ -360,7 +360,7 @@ A=100*13 = 1300pt;

- + @@ -368,7 +368,7 @@ A=100*13 = 1300pt;

- + @@ -376,7 +376,7 @@ A=100*13 = 1300pt;

- + @@ -384,7 +384,7 @@ A=100*13 = 1300pt;

- + @@ -392,7 +392,7 @@ A=100*13 = 1300pt;

- + @@ -400,7 +400,7 @@ A=100*13 = 1300pt;

- + @@ -408,7 +408,7 @@ A=100*13 = 1300pt;

- + @@ -416,7 +416,7 @@ A=100*13 = 1300pt;

- + @@ -424,7 +424,7 @@ A=100*13 = 1300pt;

- + @@ -432,7 +432,7 @@ A=100*13 = 1300pt;

- + @@ -440,7 +440,7 @@ A=100*13 = 1300pt;

- + @@ -448,7 +448,7 @@ A=100*13 = 1300pt;

- + @@ -456,7 +456,7 @@ A=100*13 = 1300pt;

- + @@ -464,7 +464,7 @@ A=100*13 = 1300pt;

- + @@ -472,7 +472,7 @@ A=100*13 = 1300pt;

- + @@ -480,7 +480,7 @@ A=100*13 = 1300pt;

- + @@ -488,7 +488,7 @@ A=100*13 = 1300pt;

- + @@ -496,7 +496,7 @@ A=100*13 = 1300pt;

- + @@ -504,7 +504,7 @@ A=100*13 = 1300pt;

- + @@ -512,7 +512,7 @@ A=100*13 = 1300pt;

- + @@ -520,7 +520,7 @@ A=100*13 = 1300pt;

- + @@ -528,7 +528,7 @@ A=100*13 = 1300pt;

- + @@ -536,7 +536,7 @@ A=100*13 = 1300pt;

- + @@ -544,7 +544,7 @@ A=100*13 = 1300pt;

- + @@ -552,7 +552,7 @@ A=100*13 = 1300pt;

- + @@ -560,7 +560,7 @@ A=100*13 = 1300pt;

- + @@ -568,7 +568,7 @@ A=100*13 = 1300pt;

- + @@ -576,7 +576,7 @@ A=100*13 = 1300pt;

- + @@ -584,7 +584,7 @@ A=100*13 = 1300pt;

- + @@ -592,7 +592,7 @@ A=100*13 = 1300pt;

- + @@ -600,7 +600,7 @@ A=100*13 = 1300pt;

- + @@ -608,7 +608,7 @@ A=100*13 = 1300pt;

- + @@ -616,7 +616,7 @@ A=100*13 = 1300pt;

- + @@ -624,7 +624,7 @@ A=100*13 = 1300pt;

- + @@ -632,7 +632,7 @@ A=100*13 = 1300pt;

- + diff --git a/t/structure/glossary.xml b/t/structure/glossary.xml index 197809d0a8..985caaaca9 100644 --- a/t/structure/glossary.xml +++ b/t/structure/glossary.xml @@ -31,7 +31,8 @@ spanning from the end of the Silurian Period to the beginning of the Carboniferous Period. This age was known for its remarkable variety of -fish species. +fish species. +Fish AgeFish Age
Diagram + Diagram + @@ -1145,7 +1145,7 @@ square.
+ @@ -1289,12 +1289,12 @@ square. +
+ @@ -1343,7 +1343,7 @@ square.
+ @@ -1376,7 +1376,7 @@ square.
+ @@ -1409,7 +1409,7 @@ square.
+ @@ -1550,12 +1550,12 @@ square. +
+ @@ -1626,7 +1626,7 @@ square.
+ @@ -1782,12 +1782,12 @@ square. +
+ @@ -1836,7 +1836,7 @@ square.
+ @@ -1889,7 +1889,7 @@ square.
+ @@ -1941,7 +1941,7 @@ square.
+ @@ -2091,12 +2091,12 @@ square. +
+ @@ -2145,7 +2145,7 @@ square.
+ @@ -2190,7 +2190,7 @@ square.
+ @@ -2250,7 +2250,7 @@ square.
+ @@ -2415,12 +2415,12 @@ square. +
+ @@ -2469,7 +2469,7 @@ square.
+ @@ -2522,7 +2522,7 @@ square.
+ @@ -2558,7 +2558,7 @@ square.
+ @@ -2708,12 +2708,12 @@ square. +
+ @@ -2792,7 +2792,7 @@ square.
+ @@ -2957,12 +2957,12 @@ square. +
+ @@ -3011,7 +3011,7 @@ square.
+ @@ -3086,7 +3086,7 @@ square.
+ diff --git a/t/graphics/xcolors.xml b/t/graphics/xcolors.xml index 24b92b1344..bb8f43e5c2 100644 --- a/t/graphics/xcolors.xml +++ b/t/graphics/xcolors.xml @@ -328,7 +328,7 @@ A=100*13 = 1300pt;

cmyk hsb HTML - gray + gray
red XX 0 1 1 0 XX 0 1 1 XX FF0000XX 0.3XX 0.3
green XX 1 0 1 0 XX 0.3333 1 1 XX 00FF00XX 0.59XX 0.59
blue XX 1 1 0 0 XX 0.6667 1 1 XX 0000FFXX 0.11XX 0.11
cyan XX 1 0 0 0 XX 0.5 1 1 XX 00FFFFXX 0.7XX 0.7
magenta XX 0 1 0 0 XX 0.8333 1 1 XX FF00FFXX 0.41XX 0.41
yellow XX 0 0 1 0 XX 0.1667 1 1 XX FFFF00XX 0.89XX 0.89
orange XX 0 0.5 1 0 XX 0.0833 1 1 XX FF8000XX 0.595XX 0.595
violet XX 0 0.5 0 0.5 XX 0.8333 1 0.5 XX 800080XX 0.205XX 0.205
purple XX 0 0.75 0.5 0.25 XX 0.9444 1 0.75 XX BF0040XX 0.2525XX 0.2525
brown XX 0 0.25 0.5 0.25 XX 0.0833 0.6667 0.75 XX BF8040XX 0.5475XX 0.5475
pink XX 0 0.25 0.25 0 XX 0 0.25 1 XX FFBFBFXX 0.825XX 0.825
olive XX 0 0 1 0.5 XX 0.1667 1 0.5 XX 808000XX 0.39XX 0.39
black XX 0 0 0 1 XX 0 0 0 XX 000000XX 0XX 0
darkgray XX 0 0 0 0.75 XX 0 0 0.25 XX 404040XX 0.25XX 0.25
gray XX 0 0 0 0.5 XX 0 0 0.5 XX 808080XX 0.5XX 0.5
lightgray XX 0 0 0 0.25 XX 0 0 0.75 XX BFBFBFXX 0.75XX 0.75
white XX 0 0 0 0 XX 0 0 1 XX FFFFFFXX 1XX 1
-red XX 1 0 0 0 XX 0.5 1 1 XX 00FFFFXX 0.7XX 0.7
-green XX 0 1 0 0 XX 0.8333 1 1 XX FF00FFXX 0.41XX 0.41
-blue XX 0 0 1 0 XX 0.1667 1 1 XX FFFF00XX 0.89XX 0.89
-cyan XX 0 1 1 0 XX 0 1 1 XX FF0000XX 0.3XX 0.3
-magenta XX 1 0 1 0 XX 0.3333 1 1 XX 00FF00XX 0.59XX 0.59
-yellow XX 1 1 0 0 XX 0.6667 1 1 XX 0000FFXX 0.11XX 0.11
-orange XX 1 0.5 0 0 XX 0.5833 1 1 XX 0080FFXX 0.405XX 0.405
-violet XX 0.5 0 0.5 0 XX 0.3333 0.5 1 XX 80FF80XX 0.795XX 0.795
-purple XX 0.75 0 0.25 0 XX 0.4444 0.75 1 XX 40FFBFXX 0.7475XX 0.7475
-brown XX 0.5 0.25 0 0.25 XX 0.5833 0.6667 0.75 XX 4080BFXX 0.4525XX 0.4525
-pink XX 0.25 0 0 0.75 XX 0.5 1 0.25 XX 004040XX 0.175XX 0.175
-olive XX 0.5 0.5 0 0 XX 0.6667 0.5 1 XX 8080FFXX 0.555XX 0.555
-black XX 0 0 0 0 XX 0 0 1 XX FFFFFFXX 1XX 1
-darkgray XX 0 0 0 0.25 XX 0 0 0.75 XX BFBFBFXX 0.75XX 0.75
-gray XX 0 0 0 0.5 XX 0 0 0.5 XX 808080XX 0.5XX 0.5
-lightgray XX 0 0 0 0.75 XX 0 0 0.25 XX 404040XX 0.25XX 0.25
-white XX 0 0 0 1 XX 0 0 0 XX 000000XX 0XX 0
JungleGreen XX 0.99 0 0.52 0 XX 0.4125 0.99 1 XX 03FF7AXX 0.6458XX 0.6458
DarkOrchid XX 0.4 0.8 0.2 0 XX 0.7778 0.75 0.8 XX 9933CCXX 0.386XX 0.386
-JungleGreen XX 0 0.99 0.47 0.01 XX 0.9125 1 0.99 XX FC0085XX 0.3542XX 0.3542
-DarkOrchid XX 0.4 0 0.6 0.2 XX 0.2778 0.75 0.8 XX 66CC33XX 0.614XX 0.614