1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
# /=====================================================================\ #
# | LaTeXML::Post::MathML::Presentation | #
# | MathML generator 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::Post::MathML::Presentation;
use strict;
use warnings;
use base qw(LaTeXML::Post::MathML);
sub preprocess {
my ($self, $doc, @maths) = @_;
$self->SUPER::preprocess($doc, @maths);
if ($$self{linelength}) { # If we're doing linebreaking...
$self->preprocess_linebreaking($doc, @maths); }
return; }
# This would be the non-linebreaking version
sub convertNode_simple {
my ($self, $doc, $xmath, $style) = @_;
return $self->pmml_top($xmath, $style); }
# Convert a node and compute it's linebroken layout
sub convertNode_linebreak {
my ($self, $doc, $xmath, $style) = @_;
my $breaker = $$self{linebreaker};
if (!$breaker) {
require LaTeXML::Post::MathML::Linebreaker;
$breaker = $$self{linebreaker} = LaTeXML::Post::MathML::Linebreaker->new(); }
my $pmml = $self->convertNode_simple($doc, $xmath, $style);
my $layout = $breaker->bestFitToWidth($xmath, $pmml, $$self{linelength}, 1);
if ($$layout{hasbreak}) { # YES it did linebreak!
$pmml = $breaker->applyLayout($pmml, $layout); }
return ($pmml, $$layout{hasbreak}); }
sub convertNode {
my ($self, $doc, $xmath) = @_;
my $style = (($xmath->parentNode->getAttribute('mode') || 'inline') eq 'display'
? 'display' : 'text');
my $id = $xmath->parentNode->getAttribute('xml:id');
# If this node has already been pre-converted
my $pmml;
if ($pmml = $id && $$doc{converted_pmml_cache}{$id}) { }
# A straight displayed Math will have been handled by preprocess_linebreaking (below),
# and, if it needed line-breaking, will have generated a MathFork/MathBranch.
# Other math, in the non-semantic side of a MathFork, may want to line break here as well.
# It presumably will NOT be display style(?)
# NEXT better strategy will be to scan columns of MathBranches to establish desired line length?
elsif ($$self{linelength} # If line breaking
&& ($doc->findnodes('ancestor::ltx:MathBranch', $xmath)) # In formatted side of MathFork?
# But ONLY if last column!! (until we can adapt LineBreaker!)
&& !$doc->findnodes('parent::ltx:Math/parent::ltx:td/following-sibling::ltx:td', $xmath)) {
my ($pmmlb, $broke) = $self->convertNode_linebreak($doc, $xmath, $style);
$pmml = $pmmlb; }
else {
$pmml = $self->convertNode_simple($doc, $xmath, $style); }
return { processor => $self, xml => $pmml, mimetype => 'application/mathml-presentation+xml' }; }
sub rawIDSuffix {
return '.pmml'; }
sub associateNodeHook {
my ($self, $node, $sourcenode) = @_;
# TODO: Shouldn't we have a single getQName shared for the entire latexml codebase
# in LaTeXML::Common or LaTeXML::Util ?
my $name = LaTeXML::Post::MathML::getQName($node);
if ($name =~ /^m:(?:mi|mo|mn)$/) {
if (my $href = $sourcenode->getAttribute('href')) {
if (ref $node eq 'ARRAY') {
$$node[1]{href} = $href; }
else {
$node->setAttribute('href', $href); } }
if (my $title = $sourcenode->getAttribute('title')) {
if (ref $node eq 'ARRAY') {
$$node[1]{title} = $title; }
else {
$node->setAttribute('title', $title); } } }
return; }
#================================================================================
# Presentation MathML with Line breaking
# Not at all sure how this will integrate with Parallel markup...
# Any displayed formula is a candidate for line-breaking.
# If it is not already in a MathFork, and needs line-breaking,
# then we ought to wrap in a MathFork, so as to preserve the
# slightly "semantically meaningful" form.
# If we're mangling the document structure in this way,
# it needs to be done before the main scan-all-math's loop,
# since it moves the maths around.
# However, since we also have to check whether it NEEDS line breaking beforehand,
# we might as well linebreak & store that line-broken result alongside.
# [it will get stored WITHOUT an XMath expression, though, so we won't be asked to redo it]
# convertNode will be called later on the main fork (unbroken).
# Also, other subexpressions inside MathFork/MathBranch that were created by
# the usual means (bindings for eqnarray, or whatever) will still need to
# be converted (convertNode).
# And in fact they also should be line-broken -- we just don't know the width!!
sub preprocess_linebreaking {
my ($self, $doc, @maths) = @_;
# Rewrap every displayed ltx:Math in an ltx:MathFork (if it isn't ALREADY in a MathFork).
# This is so that we can preserve the "more semantic" non-linebroken form as the main branch.
foreach my $math (@maths) {
my $mode = $math->getAttribute('mode') || 'inline';
next unless $mode eq 'display'; # SKIP if not in display mode?
my $style = ($mode eq 'display' ? 'display' : 'text');
# If already has in a MathBranch, we can't really know if, or how wide, to line break!?!?!
next if $doc->findnodes('ancestor::ltx:MathFork', $math); # SKIP if already in a branch?
# Now let's do the layout & see if it actually needs line breaks!
# next if $math isn't really so wide ..
my $id = $math->getAttribute('xml:id');
my $xmath = $doc->findnode('ltx:XMath', $math);
my ($pmml, $broke) = $self->convertNode_linebreak($doc, $xmath, $style);
if ($broke) { # YES it did linebreak!
# Replace the Math node with a MathFork that contains the Math node.
# And a MathBranch that ONLY contains the line-broken pmml.
# That branch won't get other parallel markup,
# but the main, more semantic(?) one, will and will get the unbroken pmml (?), as well.
my $p = $math->parentNode;
$id = $id . ".mbr" if $id;
$doc->replaceNode($math, ['ltx:MathFork', {}, $math,
['ltx:MathBranch', {},
['ltx:Math', { 'xml:id' => $id },
$self->outerWrapper($doc, $xmath, $pmml)]]]);
# Now,RE-mark, since the insertion removed internal attributes!
$doc->markXMNodeVisibility; }
# cache the converted pmml?
# But note that applyLayout MAY have MODIFIED the orignal $pmml, so it may have linebreaks!
# but then, it will have a modified id, as well!!! (.mbr appended)
if ($id) {
$$doc{converted_pmml_cache}{$id} = $pmml; }
}
return; }
#================================================================================
1;
|