From e70cdfd3a222f12ab25a8c7296b180018bc06381 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Sun, 8 Jan 2023 02:27:36 +0100 Subject: [PATCH] InsetMathBox: split the boxed text into and other tags, while boxing the whole inset within an . Rationales: - previously, was used, but it's being deprecated for MathML 4 Core in favour of CSS and (not a big deal in itself) - the whole box cannot be hosted within the same tag, because neither nor can have text, they need an intermediate container, (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 ; split the content of the cell to have text and other tags set apart (text in , other tags left as they were) Old behaviour, invalid MathML (2 to 4): text. New behaviour, valid MathML: text. --- src/mathed/InsetMathBox.cpp | 89 ++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/src/mathed/InsetMathBox.cpp b/src/mathed/InsetMathBox.cpp index f3ba7a7cb5..30cbd14356 100644 --- a/src/mathed/InsetMathBox.cpp +++ b/src/mathed/InsetMathBox.cpp @@ -25,6 +25,7 @@ #include "frontends/Painter.h" #include +#include #include 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 : split the string if there are tags. + std::vector 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 1 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 , 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'"); } -- 2.39.5