Skip to content
Open
7 changes: 4 additions & 3 deletions lib/LaTeXML/Core/Definition/Register.pm
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ sub valueOf {
sub setValue {
my ($self, $value, $scope, @args) = @_;
my $tracing = (($STATE->lookupValue('TRACING') || 0) & TRACE_COMMANDS);
my $name = '';
if ($tracing) {
my $scope = $STATE->getPrefix('global') ? 'globally ' : '';
my $csname = ToString($$self{cs});
Debug("{$scope" . "changing " . $csname . "=" . ToString($self->valueOf(@args)) . "}"); }
$name = ToString($$self{cs}).join(',',map { ToString($_); } @args);
Debug("{$scope" . "changing " . $name . "=" . ToString($self->valueOf(@args)) . "}"); }
if (my $setter = $$self{setter}) {
&{ $$self{setter} }($value, $scope, @args); }
elsif ($$self{readonly}) {
Expand All @@ -70,7 +71,7 @@ sub setValue {
else {
my $loc = (@args ? join('', $$self{address}, map { ToString($_) } @args) : $$self{address});
$STATE->assignValue($loc => $value, $scope); }
Debug("{into " . ToString($$self{cs}) . "=" . ToString($self->valueOf(@args)) . "}") if $tracing;
Debug("{into " . $name . "=" . ToString($self->valueOf(@args)) . "}") if $tracing;
return; }

sub addValue {
Expand Down
90 changes: 90 additions & 0 deletions lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,44 @@ DefParameterType('XToken', sub { $_[0]->readXToken; });
# Read a number
DefParameterType('Number', sub { $_[0]->readNumber; });

# Note that LaTeX defines several utilities, fairly heavily used,
# \setcounter, \setlength, along with \addtocounter,\addtolength
# which basically just assign a register to a Number or Dimension.
# These are typically defined in LaTeXML as {Number}, {Dimension}, or [Number],[Dimension]
# since they are read as a normal arg, but then reparsed as Number or Dimension.
# The calc package REDEFINES these to support a bit of arithmetic, or extra braces.
# Thus MANY commands suddenly accept a much wider range of expressions!
# Note also that calc actually accepts Glue expressions for Dimensions.
# [We could have calc redefine the ParameterTypes, but the internal data has already
# been incorporated into definition's Parameters objects; Thus the current hackery:]

# Read a regular arg, but content should be Number,
# or extended calc syntax if calc.sty is loaded.
DefParameterType('{Number}', sub {
my ($gullet) = @_;
my $value = $gullet->readArg();
return $gullet->readingFromMouth($value, sub {
(LookupValue('calc.sty.ltxml_loaded')
? readCalcExpression($gullet, 'Number')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This use of readCalcExpression will be a namespace headache once it reaches Rust.

The readCalcExpression sub is only available to execute (in the perl sesne) after the calc package has loaded, but it is already used in the Engine, before any bindings load. Ouch. Luckily there is late binding, but it's not easy to port.

Instead, one can have a method defined in Gullet (so always available early) with some generic name describing its behavior, maybe readArithExpression or such? And again use it only when calc is loaded. You may want to do this here, or I may just use my comment as a porting guide a bit later.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A different perl trick would have been to refactor the Engine to use a named sub for each reader:

sub named_dimension_read_sub { 
  # regular reader... 
}
DefParameterType('[Dimension]', \&named_dimension_read_sub);

and then have calc.sty.ltxml re-bind the reader sub:

*LaTeXML::Engine::Base_ParameterTypes::named_dimension_read_sub = sub {
  # new calc behavior
}

The main benefit of this approach is performance - there is never a need to do a LookupValue to check if calc is loaded. And since that will happen during every parameter read, I assume it may even be noticeably faster over large numeric files.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, it's pretty sucky all round, and all alternatives suck too.

: $gullet->readNumber()); }); },
reversion => sub {
my ($arg) = @_;
(T_BEGIN, Revert($arg), T_END); });

# Similar to {Number}, but for optional
DefParameterType('[Number]', sub {
my ($gullet) = @_;
my $value = $gullet->readOptional;
return unless $value;
return $gullet->readingFromMouth($value, sub {
(LookupValue('calc.sty.ltxml_loaded')
? readCalcExpression($gullet, 'Number')
: $gullet->readNumber()); }); },
optional => 1,
reversion => sub {
my ($arg) = @_;
return ($arg ? (T_OTHER('['), Revert($arg), T_OTHER(']')) : ()); });

# Read a floating point number
DefParameterType('Float', sub { $_[0]->readFloat; });

Expand All @@ -107,9 +145,61 @@ sub ReadFloat {
# Read a dimension
DefParameterType('Dimension', sub { $_[0]->readDimension; });

# This expects a TeX dimension, but wrapped in {}; redefinable by calc.sty
DefParameterType('{Dimension}', sub {
my ($gullet) = @_;
my $value = $gullet->readArg();
return $gullet->readingFromMouth($value, sub {
(LookupValue('calc.sty.ltxml_loaded')
? readCalcExpression($gullet, 'Glue') # Yes, calc parses a Glue for Dimensions!
: $gullet->readDimension()); }); },
reversion => sub {
my ($arg) = @_;
(T_BEGIN, Revert($arg), T_END); });

# Similar to {Dimension}, but for optional
DefParameterType('[Dimension]', sub {
my ($gullet) = @_;
my $value = $gullet->readOptional;
return unless $value;
return $gullet->readingFromMouth($value, sub {
(LookupValue('calc.sty.ltxml_loaded')
? readCalcExpression($gullet, 'Glue')
: $gullet->readDimension()); }); },
optional => 1,
reversion => sub {
my ($arg) = @_;
return ($arg ? (T_OTHER('['), Revert($arg), T_OTHER(']')) : ()); });

# Read a Glue (aka skip)
DefParameterType('Glue', sub { $_[0]->readGlue; });

# This expects a TeX Glue, but wrapped in {}; redefinable by calc.sty
DefParameterType('{Glue}', sub {
my ($gullet) = @_;
my $value = $gullet->readArg();
return $gullet->readingFromMouth($value, sub {
(LookupValue('calc.sty.ltxml_loaded')
? readCalcExpression($gullet, 'Glue')
: $gullet->readGlue()); }); },
reversion => sub {
my ($arg) = @_;
(T_BEGIN, Revert($arg), T_END); });

# Similar to {Glue}, but for optional
DefParameterType('[Glue]', sub {
my ($gullet) = @_;
my $value = $gullet->readOptional;
return unless $value;
return $gullet->readingFromMouth($value, sub {
(LookupValue('calc.sty.ltxml_loaded')
? readCalcExpression($gullet, 'Glue')
: $gullet->readGlue()); }); },
optional => 1,
reversion => sub {
my ($arg) = @_;
return ($arg ? (T_OTHER('['), Revert($arg), T_OTHER(']')) : ()); });

# Read a MuDimension (math)
DefParameterType('MuDimension', sub { $_[0]->readMuDimension; });

Expand Down
34 changes: 22 additions & 12 deletions lib/LaTeXML/Package.pm
Original file line number Diff line number Diff line change
Expand Up @@ -209,23 +209,33 @@ sub parseParameters {
$p =~ s/^\s+//; $p =~ s/\s+$//;
while ($p) {
# Handle possibly nested cases, such as {Number}
# That can be explicitly defined as {Number},
# OR will be handled as readArg, then the content reparsed as Number
if ($p =~ s/^(\{([^\}]*)\})\s*//) {
my ($spec, $inner_spec) = ($1, $2);
my $inner = ($inner_spec ? parseParameters($inner_spec, $for) : undef);
# If single inner spec is optional, make whole thing optional
my $opt = $inner && (scalar(@$inner) == 1) && $$inner[0]{optional};
push(@params, LaTeXML::Core::Parameter->new('Plain', $spec, extra => [$inner],
optional => $opt)); }
if(LookupMapping('PARAMETER_TYPES', $spec)) { # If specially defined with braces?
push(@params, LaTeXML::Core::Parameter->new($spec, $spec)); }
else {
my $inner = ($inner_spec ? parseParameters($inner_spec, $for) : undef);
# If single inner spec is optional, make whole thing optional
my $opt = $inner && (scalar(@$inner) == 1) && $$inner[0]{optional};
push(@params, LaTeXML::Core::Parameter->new('Plain', $spec, extra => [$inner],
optional => $opt)); } }
elsif ($p =~ s/^(\[([^\]]*)\])\s*//) { # Ditto for Optional
# Optional also can be defined explicitly as [Type]
# OR read using readOptional, then content (if any) reparsed as Type.
my ($spec, $inner_spec) = ($1, $2);
if ($inner_spec =~ /^Default:(.*)$/) {
push(@params, LaTeXML::Core::Parameter->new('Optional', $spec,
extra => [TokenizeInternal($1), undef])); }
elsif ($inner_spec) {
push(@params, LaTeXML::Core::Parameter->new('Optional', $spec,
extra => [undef, parseParameters($inner_spec, $for)])); }
if(LookupMapping('PARAMETER_TYPES', $spec)) { # If specially defined with []?
push(@params, LaTeXML::Core::Parameter->new($spec, $spec, optional => 1)); }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am now starting to get confused about having two ways of specifying these. I recall we also had a prefix keyword Optional, as with OptionalNumber, as well as [Number].

Shouldn't we be normalizing towards one or the other? Is there a risk that a lookup for OptionalNumber doesn't find a special mapping for [Number] or the other way around?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, but there's are Lots of the latter

else {
push(@params, LaTeXML::Core::Parameter->new('Optional', $spec)); } }
if ($inner_spec =~ /^Default:(.*)$/) {
push(@params, LaTeXML::Core::Parameter->new('Optional', $spec,
extra => [TokenizeInternal($1), undef])); }
elsif ($inner_spec) {
push(@params, LaTeXML::Core::Parameter->new('Optional', $spec,
extra => [undef, parseParameters($inner_spec, $for)])); }
else {
push(@params, LaTeXML::Core::Parameter->new('Optional', $spec)); } } }
elsif ($p =~ s/^((\w*)(:([^\s\{\[]*))?)\s*//) {
my ($spec, $type, $extra) = ($1, $2, $4);
my @extra = map { TokenizeInternal($_) } split('\|', $extra || '');
Expand Down
41 changes: 17 additions & 24 deletions lib/LaTeXML/Package/calc.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,12 @@ DefPrimitive('\heightof', '');
DefPrimitive('\ratio', '');
DefPrimitive('\real', '');

# \setcounter{<ctr>}{<integer expression>}
DefPrimitive('\setcounter{}{}', sub {
my ($stomach, $ctr, $arg) = @_;
SetCounter($ctr, readExpression($stomach->getGullet, 'Number', $arg));
return; });

# \addtocounter{<ctr>}{<integer expression>}
DefPrimitive('\addtocounter{}{}', sub {
my ($stomach, $ctr, $arg) = @_;
AddToCounter($ctr, readExpression($stomach->getGullet, 'Number', $arg));
return; });

DefPrimitive('\setlength{Variable}{}', sub {
my ($stomach, $var, $arg) = @_;
my ($defn, @args) = @$var;
return unless $defn && ($defn ne 'missing');
$defn->setValue(readExpression($stomach->getGullet, 'Glue', $arg), undef, @args); });

DefPrimitive('\addtolength{Variable}{}', sub {
my ($stomach, $var, $arg) = @_;
my ($defn, @args) = @$var;
return unless $defn && ($defn ne 'missing');
$defn->setValue($defn->valueOf(@args)->add(readExpression($stomach->getGullet, 'Glue', $arg)),
undef, @args); });
# These don't need to be redefined (from latex), since they get extended via
# the {Number},{Dimension} parameter types.
# \setcounter{<reg>}{<integer expression>}
# \addtocounter{<reg>}{<integer expression>}
# \setlength{<reg}{<glue expression>}
# \addtolength{<reg}{<glue expression>}

DefPrimitive('\settowidth{Variable} HBoxContents', sub {
my ($stomach, $var, $box) = @_;
Expand Down Expand Up @@ -120,6 +102,14 @@ sub readExpression {
$term = ($op eq '+' ? $term->add($term2) : $term->subtract($term2)); }
return $term; }); }

sub readCalcExpression {
my ($gullet, $type) = @_;
my $term = readTerm($gullet, $type);
while (my $op = $gullet->readKeyword('+', '-')) {
my $term2 = readTerm($gullet, $type);
$term = ($op eq '+' ? $term->add($term2) : $term->subtract($term2)); }
return $term; }

sub readTerm {
my ($gullet, $type) = @_;
$gullet->skipSpaces;
Expand Down Expand Up @@ -182,6 +172,9 @@ sub readValue {
# Read & Evaluate parenthesized subexpressions
elsif (Equals($peek, T_OTHER('('))) {
return readExpression($gullet, $type, $gullet->readUntil(T_OTHER(')'))); }
elsif (Equals($peek, T_BEGIN)) {
$gullet->unread($gullet->readBalanced); # Effectively strip the brace.
return readValue($gullet, $type); } # then retry
# Else read literal values.
else {
$gullet->unread($peek);
Expand Down
9 changes: 6 additions & 3 deletions lib/LaTeXML/Package/graphics.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use LaTeXML::Util::Image;
# (See LaTeXML::Post::Graphics for suggested postprocessing)
# Package options: draft, final, hiderotate, hidescale, hiresbb

# Dimensions, but \calc syntax SHOULD be allowed (if calc loaded)
# "!" (punt to other axes) or Dimension, but \calc syntax allowed if calc loaded
# [See discussions in Base_ParameterTypes for {Dimension}
DefParameterType('GraphixDimension', sub {
my ($gullet) = @_;
$gullet->skipSpaces;
Expand All @@ -32,7 +33,9 @@ DefParameterType('GraphixDimension', sub {
undef; } # essentially: let other dimensions determine size.
else {
$gullet->unread($next);
$gullet->readDimension; } },
(LookupValue('calc.sty.ltxml_loaded')
? readCalcExpression($gullet, 'Glue')
: $gullet->readDimension()); } },
optional => 1);

# For trim, viewport: a sequence of 4 dimensions
Expand Down Expand Up @@ -284,7 +287,7 @@ sub graphicX_options {
my ($key, $value) = (shift(@kv), shift(@kv));
$saw_w = 1 if $key =~ /width$/;
$saw_h = 1 if $key =~ /height$/;
$value = ToString($value);
$value = $value->toAttribute if ref $value;
$value =~ s/,/\\,/g; # Slashify any "," within the value
push(@options, $key . '=' . $value); }
push(@options, 'keepaspectratio=true') if ($saw_w xor $saw_h) && !$kv->hasKey('keepaspectratio');
Expand Down
4 changes: 2 additions & 2 deletions t/complex/figure_dual_caption.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
<tag role="typerefnum">Figure 2</tag>
</tags>
<figure align="center" class="ltx_figure_panel ltx_minipage" vattach="middle" width="172.5pt" xml:id="S0.F2.fig1">
<graphics candidates="../graphics/none.png" class="ltx_centering" graphic="../graphics/none.png" options="width=411.93767pt,keepaspectratio=true" xml:id="S0.F2.g1"/>
<graphics candidates="../graphics/none.png" class="ltx_centering" graphic="../graphics/none.png" options="width=411.9pt,keepaspectratio=true" xml:id="S0.F2.g1"/>
<toccaption class="ltx_centering"><tag close=" ">1</tag>Left figure.</toccaption>
<caption class="ltx_centering"><tag close=": ">Figure 1</tag>Left figure.</caption>
</figure>
<figure align="center" class="ltx_figure_panel ltx_minipage" vattach="middle" width="172.5pt" xml:id="S0.F2.fig2">
<graphics candidates="../graphics/none.png" class="ltx_centering" graphic="../graphics/none.png" options="width=411.93767pt,keepaspectratio=true" xml:id="S0.F2.g2"/>
<graphics candidates="../graphics/none.png" class="ltx_centering" graphic="../graphics/none.png" options="width=411.9pt,keepaspectratio=true" xml:id="S0.F2.g2"/>
<toccaption class="ltx_centering"><tag close=" ">2</tag>Right figure.</toccaption>
<caption class="ltx_centering"><tag close=": ">Figure 2</tag>Right figure.</caption>
</figure>
Expand Down
28 changes: 14 additions & 14 deletions t/complex/figure_mixed_content.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
<tag><text fontsize="90%">(a)</text></tag>
<tag role="refnum">1(a)</tag>
</tags>
<graphics candidates="../graphics/none.png" graphic="../graphics/none.png" options="width=85.35826pt,keepaspectratio=true" xml:id="S0.F1.sf1.g1"/>
<graphics candidates="../graphics/none.png" graphic="../graphics/none.png" options="width=85.4pt,keepaspectratio=true" xml:id="S0.F1.sf1.g1"/>
<toccaption><tag close=" ">(a)</tag></toccaption>
<caption><tag close=" "><text fontsize="90%">(a)</text></tag></caption>
</figure>
Expand All @@ -89,7 +89,7 @@
<tag><text fontsize="90%">(b)</text></tag>
<tag role="refnum">1(b)</tag>
</tags>
<graphics candidates="../graphics/none.png" graphic="../graphics/none.png" options="width=85.35826pt,keepaspectratio=true" xml:id="S0.F1.sf2.g1"/>
<graphics candidates="../graphics/none.png" graphic="../graphics/none.png" options="width=85.4pt,keepaspectratio=true" xml:id="S0.F1.sf2.g1"/>
<toccaption><tag close=" ">(b)</tag></toccaption>
<caption><tag close=" "><text fontsize="90%">(b)</text></tag></caption>
</figure>
Expand Down Expand Up @@ -159,10 +159,10 @@
<tag role="typerefnum">Figure 3</tag>
</tags>
<block class="ltx_figure_panel ltx_minipage" vattach="top" width="138.0pt">
<graphics candidates="../graphics/none.png" graphic="../graphics/none.png" options="width=55.1983pt,keepaspectratio=true" xml:id="S0.F3.g1"/>
<graphics candidates="../graphics/none.png" graphic="../graphics/none.png" options="width=55.2pt,keepaspectratio=true" xml:id="S0.F3.g1"/>
</block>
<block class="ltx_figure_panel ltx_minipage" vattach="top" width="138.0pt">
<graphics candidates="../graphics/none.png" graphic="../graphics/none.png" options="width=55.1983pt,keepaspectratio=true" xml:id="S0.F3.g2"/>
<graphics candidates="../graphics/none.png" graphic="../graphics/none.png" options="width=55.2pt,keepaspectratio=true" xml:id="S0.F3.g2"/>
</block>
<break/>
<itemize class="ltx_centering ltx_figure_panel" xml:id="S0.I1">
Expand Down Expand Up @@ -407,8 +407,8 @@
<tag role="refnum">5</tag>
<tag role="typerefnum">Figure 5</tag>
</tags>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F5.g1"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F5.g2"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F5.g1"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F5.g2"/>
<break class="ltx_break"/>
<p class="ltx_figure_panel">.</p>
<toccaption><tag close=" ">5</tag>Caption</toccaption>
Expand All @@ -425,13 +425,13 @@
<tag role="refnum">6</tag>
<tag role="typerefnum">Figure 6</tag>
</tags>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F6.g1"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F6.g2"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F6.g1"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F6.g2"/>
<break/>
<toccaption><tag close=" ">6</tag>mid-fig caption</toccaption>
<caption><tag close=": "><text fontsize="90%">Figure 6</text></tag><text fontsize="90%">mid-fig caption</text></caption>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F6.g3"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F6.g4"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F6.g3"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F6.g4"/>
</figure>
<pagination role="newpage"/>
<figure inlist="lof" xml:id="S0.F9">
Expand All @@ -442,13 +442,13 @@
</tags>
<toccaption><tag close=" ">7</tag>leading caption</toccaption>
<caption><tag close=": "><text fontsize="90%">Figure 7</text></tag><text fontsize="90%">leading caption</text></caption>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F9.g1"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F9.g2"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F9.g1"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F9.g2"/>
<break/>
<toccaption><tag close=" ">8</tag>mid-fig caption</toccaption>
<caption><tag close=": "><text fontsize="90%">Figure 8</text></tag><text fontsize="90%">mid-fig caption</text></caption>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F9.g3"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.85063pt,keepaspectratio=true" xml:id="S0.F9.g4"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F9.g3"/>
<graphics candidates="../graphics/none.png" class="ltx_figure_panel" graphic="../graphics/none.png" options="width=113.9pt,keepaspectratio=true" xml:id="S0.F9.g4"/>
<toccaption><tag close=" ">9</tag>trailing caption</toccaption>
<caption><tag close=": "><text fontsize="90%">Figure 9</text></tag><text fontsize="90%">trailing caption</text></caption>
</figure>
Expand Down
Binary file modified t/graphics/calc.pdf
Binary file not shown.
Loading
Loading