diff options
author | Norbert Preining <norbert@preining.info> | 2022-02-19 03:02:56 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2022-02-19 03:02:56 +0000 |
commit | 1db3acf2bbb07034aafc552f322633a96b748cf4 (patch) | |
tree | 01227822acc2f3b2641e108b814d38c64031ff4e /support/make4ht/domfilters/make4ht-mathmlfixes.lua | |
parent | 41041c6bdcedcc33698491c2caec4cd725a4fe97 (diff) |
CTAN sync 202202190302
Diffstat (limited to 'support/make4ht/domfilters/make4ht-mathmlfixes.lua')
-rw-r--r-- | support/make4ht/domfilters/make4ht-mathmlfixes.lua | 129 |
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 |