From 7feffb89e931973bc1e9f3b2622724baca656df7 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 1 Oct 2024 23:53:30 +0200 Subject: [PATCH] MathML: let the user change the MathML version. Discussed in https://www.lyx.org/trac/ticket/13058. --- development/FORMAT | 7 +- lib/lyx2lyx/lyx_2_5.py | 46 +- src/Buffer.cpp | 7 +- src/BufferParams.cpp | 8 +- src/BufferParams.h | 8 +- src/CutAndPaste.cpp | 2 +- src/OutputParams.h | 3 +- src/frontends/qt/GuiDocument.cpp | 8 + src/frontends/qt/ui/OutputUi.ui | 915 ++++++++++++++++------------- src/mathed/InsetMathBox.cpp | 12 +- src/mathed/InsetMathEnsureMath.cpp | 3 +- src/mathed/InsetMathHull.cpp | 8 +- src/tex2lyx/Preamble.cpp | 4 +- src/tex2lyx/Preamble.h | 1 + src/version.h | 4 +- 15 files changed, 604 insertions(+), 432 deletions(-) diff --git a/development/FORMAT b/development/FORMAT index 71caf03107..33bf801586 100644 --- a/development/FORMAT +++ b/development/FORMAT @@ -7,7 +7,12 @@ changes happened in particular if possible. A good example would be ----------------------- -2024-08-25 Jürgen Spitzmüller +2024-09-29 Thibaut Cuvelier + * Format incremented to 631: Add support for MathML versions, which + are stored separately for DocBook and XHTML (\docbook_mathml_version, + which is new, and \html_math_output, which receives a new value). + +2024-08-25 Jürgen Spitzmüller * Format incremented to 630: Add support for a number of languages in babel and polyglossia: Polyglossia: Chinese (Simplified), Chinese (Traditional), Japanese, Kurdish (Sorani), diff --git a/lib/lyx2lyx/lyx_2_5.py b/lib/lyx2lyx/lyx_2_5.py index ef9d4afd44..b732c06765 100644 --- a/lib/lyx2lyx/lyx_2_5.py +++ b/lib/lyx2lyx/lyx_2_5.py @@ -1015,6 +1015,48 @@ def revert_new_babel_languages(document): if document.language == "hebrew" or find_token(document.body, "\\lang oldrussian", 0) != -1: add_to_preamble(document, ["\\PassOptionsToPackage{provide*=*}{babel}"]) + +def convert_mathml_version(document): + """Add MathML version header for DocBook to use MathML 3 preferably. + + For cleanliness, add this header close to other DocBook headers if present. + + Leave XHTML alone, as the default value is still probably what the user wants (MathML Core).""" + + i = find_token(document.header, "\\docbook", 0) + if i == -1: + document.header += ["\\docbook_mathml_version 0"] + else: + document.header.insert(i + 1, "\\docbook_mathml_version 0") + + +def revert_mathml_version(document): + """Remove MathML version header. + + For XHTML, only remove the value 4 for \html_math_output (MathML 3) and replace it with 0 + (MathML Core with format 631+, MathML for 630-). + + For DocBook, totally remove the header (the default with 630- is MathML).""" + + while True: + i = find_token(document.header, "\\html_math_output", 0) + if i == -1: + # nothing to do + break + + # remove XHTML header if using the new value, leave alone otherwise. + if "4" in document.header: + document.header[i] = "\\html_math_output 0" + + while True: + i = find_token(document.header, "\\docbook_mathml_version", 0) + if i == -1: + # nothing to do + return + + # remove header + del document.header[i] + ## # Conversion hub # @@ -1030,11 +1072,13 @@ convert = [ [627, [convert_nomencl, convert_index_sc]], [628, []], [629, []], - [630, []] + [630, []], + [631, [convert_mathml_version]] ] revert = [ + [630, [revert_mathml_version]], [629, [revert_new_polyglossia_languages, revert_new_babel_languages]], [628, [revert_langopts]], [627, [revert_nomentbl]], diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 73f627646b..222a146d35 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -4472,8 +4472,11 @@ void Buffer::setMathFlavor(OutputParams & op) const // In particular, this function has no impact on the DocBook code, as it // uses another mechanism to handle math flavours. switch (params().html_math_output) { - case BufferParams::MathML: - op.math_flavor = OutputParams::MathAsMathML; + case BufferParams::MathMLCore: + op.math_flavor = OutputParams::MathAsMathMLCore; + break; + case BufferParams::MathML3: + op.math_flavor = OutputParams::MathAsMathML3; break; case BufferParams::HTML: op.math_flavor = OutputParams::MathAsHTML; diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index cc73b016ca..88b7242492 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -480,11 +480,12 @@ BufferParams::BufferParams() // default index indiceslist().addDefault(B_("Index")); html_be_strict = false; - html_math_output = MathML; + html_math_output = MathMLCore; html_math_img_scale = 1.0; html_css_as_file = false; docbook_table_output = HTMLTable; docbook_mathml_prefix = MPrefix; + docbook_mathml_version = MathMLStream::mathml3; display_pixel_ratio = 1.0; shell_escape = false; @@ -1226,6 +1227,10 @@ string BufferParams::readToken(Lexer & lex, string const & token, int temp; lex >> temp; docbook_mathml_prefix = static_cast(temp); + } else if (token == "\\docbook_mathml_version") { + int temp; + lex >> temp; + docbook_mathml_version = static_cast(temp); } else if (token == "\\output_sync") { lex >> output_sync; } else if (token == "\\output_sync_macro") { @@ -1621,6 +1626,7 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const os << "\\docbook_table_output " << docbook_table_output << '\n'; os << "\\docbook_mathml_prefix " << docbook_mathml_prefix << '\n'; + os << "\\docbook_mathml_version " << docbook_mathml_version << '\n'; if (html_math_img_scale != 1.0) os << "\\html_math_img_scale " << convert(html_math_img_scale) << '\n'; diff --git a/src/BufferParams.h b/src/BufferParams.h index 73541c1b08..541f8e3fe8 100644 --- a/src/BufferParams.h +++ b/src/BufferParams.h @@ -28,6 +28,8 @@ #include #include +#include "mathed/MathStream.h" + namespace lyx { namespace support { @@ -587,7 +589,8 @@ public: // do not change these values. we rely upon them. enum MathOutput { - MathML = 0, + MathMLCore = 0, + MathML3 = 4, HTML = 1, Images = 2, LaTeX = 3 @@ -625,6 +628,9 @@ public: /// what prefix to use when outputting MathML. present choices are above MathMLNameSpacePrefix docbook_mathml_prefix; + /// what version of MathML to use for DocBook output (likely different from the version used for XHTML) + MathMLStream::MathMLVersion docbook_mathml_version; + /// allow the LaTeX backend to run external programs bool shell_escape; /// generate output usable for reverse/forward search diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index 3de2a92a73..ffd4dfa10d 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -658,7 +658,7 @@ void putClipboard(ParagraphList const & paragraphs, // We don't want to produce images that are not used. Therefore, // output formulas as MathML. Even if this is not understood by all // applications, the number that can parse it should go up in the future. - buffer->params().html_math_output = BufferParams::MathML; + buffer->params().html_math_output = BufferParams::MathMLCore; // Copy authors to the params. We need those pointers. for (Author const & a : bp.authors()) diff --git a/src/OutputParams.h b/src/OutputParams.h index b063653b8a..47798a3456 100644 --- a/src/OutputParams.h +++ b/src/OutputParams.h @@ -54,7 +54,8 @@ class OutputParams { public: enum MathFlavor { NotApplicable, - MathAsMathML, + MathAsMathMLCore, + MathAsMathML3, MathAsHTML, MathAsImages, MathAsLaTeX diff --git a/src/frontends/qt/GuiDocument.cpp b/src/frontends/qt/GuiDocument.cpp index cf4cc1ca27..4e41d8e8c2 100644 --- a/src/frontends/qt/GuiDocument.cpp +++ b/src/frontends/qt/GuiDocument.cpp @@ -952,6 +952,8 @@ GuiDocument::GuiDocument(GuiView & lv) this, SLOT(change_adaptor())); connect(outputModule->mathmlprefixCB, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor())); + connect(outputModule->mathmlverCB, SIGNAL(currentIndexChanged(int)), + this, SLOT(change_adaptor())); connect(outputModule->shellescapeCB, SIGNAL(stateChanged(int)), this, SLOT(shellescapeChanged())); @@ -4076,6 +4078,12 @@ void GuiDocument::applyView() auto const mp = static_cast(mathmlprefix); bp_.docbook_mathml_prefix = mp; + int mathmlversion = outputModule->mathmlverCB->currentIndex(); + if (mathmlversion == -1) + mathmlversion = 0; + auto const mv = static_cast(mathmlversion); + bp_.docbook_mathml_version = mv; + bp_.save_transient_properties = outputModule->saveTransientPropertiesCB->isChecked(); bp_.postpone_fragile_content = diff --git a/src/frontends/qt/ui/OutputUi.ui b/src/frontends/qt/ui/OutputUi.ui index e18dc118fe..842cd4fa94 100644 --- a/src/frontends/qt/ui/OutputUi.ui +++ b/src/frontends/qt/ui/OutputUi.ui @@ -6,396 +6,228 @@ 0 0 - 702 - 501 + 579 + 465 Form - + - - - - - - 0 - 0 - - - - LyX Format - - - true - - - false - - - - - - Save all parameters in the LyX file, including ones that are frequently switched or that are specific to the user (such as the output of the tracked changes, or the document directory path). Disabling this option plays nicer in collaborative settings and with version control systems. - - - Save &transient properties - - - - - - - - - - - 0 - 0 - - - - Output Format - - - true - - - - 9 + + + + 0 + 0 + + + + LyX Format + + + true + + + false + + + + + + Save all parameters in the LyX file, including ones that are frequently switched or that are specific to the user (such as the output of the tracked changes, or the document directory path). Disabling this option plays nicer in collaborative settings and with version control systems. - - 9 - - - 9 - - - 9 + + Save &transient properties + + + + + + + + + + 0 + 0 + + + + Output Format + + + true + + + + 9 + + + 9 + + + 9 + + + 9 + + + 6 + + + 6 - - - - 6 + + 0 + + + 0 + + + 0 + + + 0 + + + + + Specify the default output format (for view/update) - - 0 + + De&fault output format: - - 0 + + defaultFormatCO - - 0 + + + + + + Specify the default output format (for view/update) - - 0 + + + + + + Qt::Horizontal - - - - Specify the default output format (for view/update) - - - De&fault output format: - - - defaultFormatCO - - - - - - - Specify the default output format (for view/update) - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - + + + 40 + 20 + + + - - - - - - - 0 - 0 - - - - Output Options - - - - - - - - - false - - + + + + + + + + + 0 + 0 + + + + Output Options + + + + + + + 0 + 0 + + + + 0 + + + + &LaTeX + + + + - Scaling factor for images that are generated for some LaTeX constructs (e.g., math formulae) in non-LaTeX output. + If this is checked, fragile items such as labels and index entries are moved out of moving arguments such as sections and captions. This prevents LaTeX errors that can happen in such cases. It is recommended to keep this on. - Scaling of generated &images: - - - mathimgSB + Put fra&gile content out of moving arguments - - - - - false - - - - Scaling factor for images that are generated for some LaTeX constructs (e.g., math formulae) in non-LaTeX output. - - - 0.100000000000000 - - - 10.000000000000000 - - - 0.100000000000000 - - - 1.000000000000000 - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - 0 - - - - 0 - - - - &LaTeX - - - - + + + + - If this is checked, fragile items such as labels and index entries are moved out of moving arguments such as sections and captions. This prevents LaTeX errors that can happen in such cases. It is recommended to keep this on. + Enable forward/reverse search between editor and output (e.g., SyncTeX) - Put fra&gile content out of moving arguments + S&ynchronize with output - - - - - - Enable forward/reverse search between editor and output (e.g., SyncTeX) - - - S&ynchronize with output - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Fixed - - - - 20 - 20 - - - - - - - - - - - 0 - 0 - - - - C&ustom macro: - - - synccustomCB - - - - - - - Custom LaTeX preamble macro - - - true - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + - - - - - &XHTML - - - - + + - - - Whether to comply strictly with XHTML 1.1. + + + + 0 + 0 + - &Strict XHTML 1.1 - - - - - - - Write CSS to file - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - false - - - - &Math output: + C&ustom macro: - tableoutCB + synccustomCB - - - - false - - + - Format to use for math output. + Custom LaTeX preamble macro + + + true - - - MathML - - - - - HTML - - - - - Images - - - - - LaTeX - - - + - Qt::Orientation::Horizontal + Qt::Horizontal @@ -408,29 +240,169 @@ - - - - &DocBook - + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + &XHTML + + + + + + + + + false + + + + &Math output: + + + mathmlverCB + + + + + + + + false + + + + Format to use for math output. + + + + MathML Core (default) + + + + + MathML 3 + + + + + HTML + + + + + Images + + + + + LaTeX + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Whether to comply strictly with XHTML 1.1. + + + &Strict XHTML 1.1 + + + + + + + Write CSS to file + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + &DocBook + + + - - - - - - false - - - - &Table output: - - - tableoutCB - - - + + + + false + + + + &Table output: + + + mathmlverCB + + + + + @@ -462,11 +434,11 @@ - Qt::Orientation::Horizontal + Qt::Horizontal - 178 + 320 38 @@ -474,25 +446,25 @@ - - + + + + + false + + + + MathML &version: + + + mathmlverCB + + + + + - - - - false - - - - &MathML namespace prefix: - - - mathmlprefixCB - - - - - + 0 @@ -505,66 +477,181 @@ - Namespace prefix to use for MathML formulae. For instance, with the <code>m</code> prefix, the MathML tags will be output like <code>m:math</code>. + Format to use for math output. - No prefix (namespace defined inline for each tag) + MathML 3 (default) - m (default) - - - - - mml + MathML Core - + - Qt::Orientation::Horizontal + Qt::Horizontal - 148 - 28 + 40 + 20 + + + + + false + + + + &MathML namespace prefix: + + + mathmlprefixCB + + + + + + + + 0 + 0 + + + + + false + + + + Namespace prefix to use for MathML formulae. For instance, with the <code>m</code> prefix, the MathML tags will be output like <code>m:math</code>. + + + + No prefix (namespace defined inline for each tag) + + + + + m (default) + + + + + mml + + + + - + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + false + + + + Scaling factor for images that are generated for some LaTeX constructs (e.g., math formulae) in non-LaTeX output. + + + Scaling of generated &images: + + + mathimgSB + + + + + + false + + + + Scaling factor for images that are generated for some LaTeX constructs (e.g., math formulae) in non-LaTeX output. + + + 0.100000000000000 + + + 10.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + - - - - - - Runs the LaTeX backend with the -shell-escape option (Warning: use only when really necessary) - - - &Allow running external programs - - - - + + + - + + + + Runs the LaTeX backend with the -shell-escape option (Warning: use only when really necessary) + + + &Allow running external programs + + + + - Qt::Orientation::Vertical + Qt::Vertical - QSizePolicy::Policy::Expanding + QSizePolicy::Expanding diff --git a/src/mathed/InsetMathBox.cpp b/src/mathed/InsetMathBox.cpp index 62a11a15aa..abdb2128b4 100644 --- a/src/mathed/InsetMathBox.cpp +++ b/src/mathed/InsetMathBox.cpp @@ -119,7 +119,8 @@ void InsetMathBox::validate(LaTeXFeatures & features) const // FIXME XHTML // It'd be better to be able to get this from an InsetLayout, but at present // InsetLayouts do not seem really to work for things that aren't InsetTexts. - if (features.runparams().math_flavor == OutputParams::MathAsMathML) + if (features.runparams().math_flavor == OutputParams::MathAsMathMLCore || + features.runparams().math_flavor == OutputParams::MathAsMathML3) features.addCSSSnippet("mtext.mathbox { font-style: normal; }"); else if (features.runparams().math_flavor == OutputParams::MathAsHTML) features.addCSSSnippet("span.mathbox { font-style: normal; }"); @@ -204,7 +205,8 @@ void InsetMathFBox::validate(LaTeXFeatures & features) const // FIXME XHTML // It'd be better to be able to get this from an InsetLayout, but at present // InsetLayouts do not seem really to work for things that aren't InsetTexts. - if (features.runparams().math_flavor == OutputParams::MathAsMathML) + if (features.runparams().math_flavor == OutputParams::MathAsMathMLCore || + features.runparams().math_flavor == OutputParams::MathAsMathML3) features.addCSSSnippet( "mtext.fbox { border: 1px solid black; font-style: normal; padding: 0.5ex; }"); else if (features.runparams().math_flavor == OutputParams::MathAsHTML) @@ -343,7 +345,8 @@ void InsetMathMakebox::validate(LaTeXFeatures & features) const // FIXME XHTML // It'd be better to be able to get this from an InsetLayout, but at present // InsetLayouts do not seem really to work for things that aren't InsetTexts. - if (features.runparams().math_flavor == OutputParams::MathAsMathML) + if (features.runparams().math_flavor == OutputParams::MathAsMathMLCore || + features.runparams().math_flavor == OutputParams::MathAsMathML3) features.addCSSSnippet("mtext.framebox { border: 1px solid black; }"); else if (features.runparams().math_flavor == OutputParams::MathAsHTML) features.addCSSSnippet("span.framebox { border: 1px solid black; }"); @@ -423,7 +426,8 @@ void InsetMathBoxed::validate(LaTeXFeatures & features) const // FIXME XHTML // It'd be better to be able to get this from an InsetLayout, but at present // InsetLayouts do not seem really to work for things that aren't InsetTexts. - if (features.runparams().math_flavor == OutputParams::MathAsMathML) + if (features.runparams().math_flavor == OutputParams::MathAsMathMLCore || + features.runparams().math_flavor == OutputParams::MathAsMathML3) features.addCSSSnippet("mtext.boxed { border: 1px solid black; }"); else if (features.runparams().math_flavor == OutputParams::MathAsHTML) features.addCSSSnippet("span.boxed { border: 1px solid black; }"); diff --git a/src/mathed/InsetMathEnsureMath.cpp b/src/mathed/InsetMathEnsureMath.cpp index 7f82345efd..bf325d1475 100644 --- a/src/mathed/InsetMathEnsureMath.cpp +++ b/src/mathed/InsetMathEnsureMath.cpp @@ -98,7 +98,8 @@ void InsetMathEnsureMath::validate(LaTeXFeatures & features) const // FIXME XHTML // It'd be better to be able to get this from an InsetLayout, but at present // InsetLayouts do not seem really to work for things that aren't InsetTexts. - if (features.runparams().math_flavor == OutputParams::MathAsMathML) + if (features.runparams().math_flavor == OutputParams::MathAsMathMLCore || + features.runparams().math_flavor == OutputParams::MathAsMathML3) features.addCSSSnippet("mstyle.math { font-style: italic; }"); else if (features.runparams().math_flavor == OutputParams::MathAsHTML) features.addCSSSnippet("span.mathbox { font-style: italic; }"); diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index 83fffc3be6..bf04577e4f 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -2655,9 +2655,13 @@ docstring InsetMathHull::xhtml(XMLStream & xs, OutputParams const & op) const } // FIXME Eventually we would like to do this inset by inset. - if (mathtype == BufferParams::MathML) { + if (mathtype == BufferParams::MathML3 || mathtype == BufferParams::MathMLCore) { + MathMLStream::MathMLVersion mathml_version = MathMLStream::mathmlCore; + if (mathtype == BufferParams::MathML3) + mathml_version = MathMLStream::mathml3; + odocstringstream os; - MathMLStream ms(os, "", MathMLStream::mathmlCore); + MathMLStream ms(os, "", mathml_version); try { mathmlize(ms); success = true; diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 5f0043e042..84994fddac 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -552,7 +552,7 @@ Preamble::Preamble() : one_language(true), explicit_babel(false), // h_font_roman_opts; // h_font_sans_opts; // h_font_typewriter_opts; - //h_font_cjk + // h_font_cjk h_is_mathindent = "0"; h_math_numbering_side = "default"; h_graphics = "default"; @@ -562,6 +562,7 @@ Preamble::Preamble() : one_language(true), explicit_babel(false), h_html_math_output = "0"; h_docbook_table_output = "0"; h_docbook_mathml_prefix = "1"; + h_docbook_mathml_version = "0"; h_index[0] = "Index"; h_index_command = "default"; h_inputencoding = "auto-legacy"; @@ -2168,6 +2169,7 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled << "\\html_be_strict " << h_html_be_strict << "\n" << "\\docbook_table_output " << h_docbook_table_output << "\n" << "\\docbook_mathml_prefix " << h_docbook_mathml_prefix << "\n" + << "\\docbook_mathml_version " << h_docbook_mathml_version << "\n" << authors_ << "\\end_header\n\n" << "\\begin_body\n"; diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index 01d29fcf54..8670a92596 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -199,6 +199,7 @@ private: std::string h_html_math_output; std::string h_docbook_table_output; std::string h_docbook_mathml_prefix; + std::string h_docbook_mathml_version; std::string h_index[99]; std::string h_index_command; std::string h_inputencoding; diff --git a/src/version.h b/src/version.h index 1e18ff3816..abba5890fa 100644 --- a/src/version.h +++ b/src/version.h @@ -32,8 +32,8 @@ extern char const * const lyx_version_info; // Do not remove the comment below, so we get merge conflict in // independent branches. Instead add your own. -#define LYX_FORMAT_LYX 630 // spitz: language updates -#define LYX_FORMAT_TEX2LYX 630 +#define LYX_FORMAT_LYX 631 // tcuvelier: add MathML version +#define LYX_FORMAT_TEX2LYX 631 #if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX #ifndef _MSC_VER