commit e70cdfd3a222f12ab25a8c7296b180018bc06381 Author: Thibaut Cuvelier <tcuvel...@lyx.org> Date: Sun Jan 8 02:27:36 2023 +0100
InsetMathBox: split the boxed text into <mtext> and other tags, while boxing the whole inset within an <mrow>. Rationales: - previously, <mstyle> was used, but it's being deprecated for MathML 4 Core in favour of CSS and <mrow> (not a big deal in itself) - the whole box cannot be hosted within the same tag, because neither <mstyle> nor <mrow> can have text, they need an intermediate container, <mtext> (which cannot hold anything else that pure text) - new behaviour: always output a container for the whole box that has the right attributes, i.e. an <mrow>; split the content of the cell to have text and other tags set apart (text in <mtext>, other tags left as they were) Old behaviour, invalid MathML (2 to 4): <mstyle XXX>text<mn>.</mn></mstyle> New behaviour, valid MathML: <mrow XXX><mtext>text</mtext><mn>.</mn></mrow> --- src/mathed/InsetMathBox.cpp | 89 +++++++++++++++++++++++++++++++++++------- 1 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/mathed/InsetMathBox.cpp b/src/mathed/InsetMathBox.cpp index f3ba7a7..30cbd14 100644 --- a/src/mathed/InsetMathBox.cpp +++ b/src/mathed/InsetMathBox.cpp @@ -25,6 +25,7 @@ #include "frontends/Painter.h" #include <algorithm> +#include <iostream> #include <ostream> using namespace lyx::support; @@ -57,16 +58,82 @@ void InsetMathBox::normalize(NormalStream & os) const } +namespace { +void splitAndWrapInMText(MathMLStream & ms, MathData const & cell, + const std::string & attributes) +{ + // First, generate the inset into a string of its own. + docstring inset_contents; + { + odocstringstream ostmp; + MathMLStream mstmp(ostmp, ms.xmlns()); + + SetMode textmode(mstmp, true); + mstmp << cell; + + inset_contents = ostmp.str(); + } + + std::cout << '"' << to_ascii(inset_contents) << '"' << std::endl; + + // No tags are allowed within <m:mtext>: split the string if there are tags. + std::vector<docstring> parts; + while (true) { + std::size_t angle_pos = inset_contents.find('<'); + if (angle_pos == docstring::npos) + break; + + // String structure: + // - prefix: pure text, no tag + // - tag to split: something like <m:mn>1</m:mn> or more complicated + // (like nested tags), with or without name space + // - rest to be taken care of in the next iteration + + // Push the part before the tag. + parts.emplace_back(inset_contents.substr(0, angle_pos)); + inset_contents = inset_contents.substr(angle_pos); + // Now, inset_contents starts with the tag to isolate, so that + // inset_contents[0] == '<' + + // Push the tag, up to its end. Process: find the tag name (either + // before > or the first attribute of the tag), then the matching end + // tag, then proceed with pushing. + const std::size_t tag_name_end = + std::min(inset_contents.find(' ', 1), inset_contents.find('>', 1)); + const std::size_t tag_name_length = tag_name_end - 1; + const docstring tag_name = inset_contents.substr(1, tag_name_length); + + const std::size_t end_tag_start = + inset_contents.find(tag_name, tag_name_end + 1); + const std::size_t end_tag = inset_contents.find('>', end_tag_start); + + parts.emplace_back(inset_contents.substr(0, end_tag + 1)); + inset_contents = inset_contents.substr(end_tag + 1); + } + parts.emplace_back(inset_contents); + + // Finally, output the complete inset: escape the test in <m:mtext>, leave + // the other tags untouched. + ms << MTag("mrow", attributes); + for (int i = 0; i < parts.size(); i += 2) { + ms << MTag("mtext") + << parts[i] + << ETag("mtext"); + if (parts.size() > i + 1) + ms << parts[i + 1]; + } + ms << ETag("mrow"); +} +} + + void InsetMathBox::mathmlize(MathMLStream & ms) const { // FIXME XHTML // Need to do something special for tags here. // Probably will have to involve deferring them, which // means returning something from this routine. - SetMode textmode(ms, true); - ms << MTag("mtext", "class='mathbox'") - << cell(0) - << ETag("mtext"); + splitAndWrapInMText(ms, cell(0), "class='mathbox'"); } @@ -165,10 +232,7 @@ void InsetMathFBox::normalize(NormalStream & os) const void InsetMathFBox::mathmlize(MathMLStream & ms) const { - SetMode textmode(ms, true); - ms << MTag("mtext", "class='fbox'") - << cell(0) - << ETag("mtext"); + splitAndWrapInMText(ms, cell(0), "class='fbox'"); } @@ -311,10 +375,7 @@ void InsetMathMakebox::mathmlize(MathMLStream & ms) const { // FIXME We could do something with the other arguments. std::string const cssclass = framebox_ ? "framebox" : "makebox"; - SetMode textmode(ms, true); - ms << MTag("mtext", "class='" + cssclass + "'") - << cell(2) - << ETag("mtext"); + splitAndWrapInMText(ms, cell(2), "class='" + cssclass + "'"); } @@ -393,9 +454,7 @@ void InsetMathBoxed::infoize(odocstream & os) const void InsetMathBoxed::mathmlize(MathMLStream & ms) const { - ms << MTag("mtext", "class='boxed'") - << cell(0) - << ETag("mtext"); + splitAndWrapInMText(ms, cell(0), "class='boxed'"); } -- lyx-cvs mailing list lyx-cvs@lists.lyx.org http://lists.lyx.org/mailman/listinfo/lyx-cvs