summaryrefslogtreecommitdiff
path: root/support/make4ht/domfilters/make4ht-mathmlfixes.lua
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-02-19 03:02:56 +0000
committerNorbert Preining <norbert@preining.info>2022-02-19 03:02:56 +0000
commit1db3acf2bbb07034aafc552f322633a96b748cf4 (patch)
tree01227822acc2f3b2641e108b814d38c64031ff4e /support/make4ht/domfilters/make4ht-mathmlfixes.lua
parent41041c6bdcedcc33698491c2caec4cd725a4fe97 (diff)
CTAN sync 202202190302
Diffstat (limited to 'support/make4ht/domfilters/make4ht-mathmlfixes.lua')
-rw-r--r--support/make4ht/domfilters/make4ht-mathmlfixes.lua129
1 files changed, 125 insertions, 4 deletions
diff --git a/support/make4ht/domfilters/make4ht-mathmlfixes.lua b/support/make4ht/domfilters/make4ht-mathmlfixes.lua
index 42f1e55775..12754bedb9 100644
--- a/support/make4ht/domfilters/make4ht-mathmlfixes.lua
+++ b/support/make4ht/domfilters/make4ht-mathmlfixes.lua
@@ -1,3 +1,4 @@
+local log = logging.new("mathmlfixes")
-- <mglyph> should be inside <mi>, so we don't process it
-- even though it is a token element
local token = {"mi", "mn", "mo", "mtext", "mspace", "ms"}
@@ -37,20 +38,57 @@ local function fix_nested_mstyle(el)
end
end
--- if element contains
--- wrap everything in <mrow>
+local function fix_mathvariant(el)
+ -- set mathvariant of <mi> that is child of <mstyle> to have the same value
+ local function find_mstyle(x)
+ -- find if element has <mstyle> parent, and its value of mathvariant
+ if not x:is_element() then
+ return nil
+ elseif x:get_element_name() == "mstyle" then
+ return x:get_attribute("mathvariant")
+ else
+ return find_mstyle(x:get_parent())
+ end
+ end
+ if el:get_element_name() == "mi" then
+ -- process only <mi> that have mathvariant set
+ local oldmathvariant = el:get_attribute("mathvariant")
+ if oldmathvariant then
+ local mathvariant = find_mstyle(el:get_parent())
+ if mathvariant then
+ el:set_attribute("mathvariant", mathvariant)
+ end
+ end
+ end
+end
+
+-- put <mrow> as child of <math> if it already isn't here
+local allowed_top_mrow = {
+ math=true
+}
local function top_mrow(math)
local children = math:get_children()
local put_mrow = false
-- don't process elements with one or zero children
-- don't process elements that already are mrow
- if #children < 2 or math:get_element_name() == "mrow" then return nil end
+ local parent = math:get_parent()
+ local parent_name
+ if parent then parent_name = parent:get_element_name() end
+ local current_name = math:get_element_name()
+ if #children < 2 or not allowed_top_mrow[current_name] or current_name == "mrow" or parent_name == "mrow" then return nil end
+ local mrow_count = 0
for _,v in ipairs(children) do
if v:is_element() and is_token_element(v) then
put_mrow = true
- break
+ -- break
+ elseif v:is_element() and v:get_element_name() == "mrow" then
+ mrow_count = mrow_count + 1
end
end
+ if not put_mrow and math:get_element_name() == "math" and mrow_count == 0 then
+ -- put at least one <mrow> to each <math>
+ put_mrow = true
+ end
if put_mrow then
local mrow = math:create_element("mrow")
for _, el in ipairs(children) do
@@ -122,6 +160,86 @@ local function fix_mo_to_mfenced(el)
end
end
+local function fix_numbers(el)
+ -- convert <mn>1</mn><mo>.</mo><mn>3</mn> to <mn>1.3</mn>
+ if el:get_element_name() == "mn" then
+ local n = el:get_sibling_node(1)
+ -- test if next element is <mo class="MathClass-punc">.</mo>
+ if n and n:is_element()
+ and n:get_element_name() == "mo"
+ and n:get_attribute("class") == "MathClass-punc"
+ and n:get_text() == "."
+ then
+ -- get next element and test if it is <mn>
+ local x = el:get_sibling_node(2)
+ if x and x:is_element()
+ and x:get_element_name() == "mn"
+ then
+ -- join numbers and set it as text content of the current element
+ local newnumber = el:get_text() .. "." .. x:get_text()
+ log:debug("Joining numbers: " .. newnumber)
+ el._children = {}
+ local newchild = el:create_text_node(newnumber)
+ el:add_child_node(newchild)
+ -- remove elements that hold dot and decimal part
+ n:remove_node()
+ x:remove_node()
+ end
+ end
+ end
+end
+
+
+local function just_operators(list)
+ -- count <mo> and return true if list contains just them
+ local mo = 0
+ for _, x in ipairs(list) do
+ if x:get_element_name() == "mo" then mo = mo + 1 end
+ end
+ return mo
+end
+
+
+local function fix_operators(x)
+ -- change <mo> elements that are only children of any element to <mi>
+ -- this fixes issues in LibreOffice with a^{*}
+ -- I hope it doesn't introduce different issues
+ -- process only <mo>
+ if x:get_element_name() ~= "mo" then return nil end
+ local siblings = x:get_siblings()
+ -- test if current element list contains only <mo>
+ if just_operators(siblings) == #siblings then
+ if #siblings == 1 then
+ -- one <mo> translates to <mtext>
+ x._name = "mtext"
+ log:debug("changing one <mo> to <mtext>: " .. x:get_text())
+ -- I think we should use <mi>, but LO incorrectly renders it in <msubsup>,
+ -- even if we use the mathvariant="normal" attribute. <mtext> works, so
+ -- we use that instead.
+ -- x:set_attribute("mathvariant", "normal")
+ else
+ -- multiple <mo> translate to <mtext>
+ local text = {}
+ for _, el in ipairs(siblings) do
+ text[#text+1] = el:get_text()
+ end
+ -- replace first <mo> text with concetanated text content
+ -- of all <mo> elements
+ x._children = {}
+ local newtext = table.concat(text)
+ local text_el = x:create_text_node(newtext)
+ log:debug("changing <mo> to <mtext>: " .. newtext)
+ x:add_child_node(text_el)
+ -- change <mo> to <mtext>
+ x._name = "mtext"
+ -- remove subsequent <mo>
+ for i = 2, #siblings do
+ siblings[i]:remove_node()
+ end
+ end
+ end
+end
+
return function(dom)
dom:traverse_elements(function(el)
if settings.output_format ~= "odt" then
@@ -132,6 +250,9 @@ return function(dom)
end
fix_token_elements(el)
fix_nested_mstyle(el)
+ fix_numbers(el)
+ fix_operators(el)
+ fix_mathvariant(el)
top_mrow(el)
end)
return dom