From fafe3ea5d7be1c06fb734e3bc621c551d617a6f7 Mon Sep 17 00:00:00 2001 From: Richard Kimberly Heck Date: Sun, 23 Jun 2024 12:37:25 -0400 Subject: [PATCH] Fix bug #13069. Use XML parser to handle issues. Some of the config/qt.m4 code by JMarc. --- config/qt.m4 | 14 +++--- src/mathed/InsetMathBox.cpp | 95 +++++++++++++++++++------------------ 2 files changed, 56 insertions(+), 53 deletions(-) diff --git a/config/qt.m4 b/config/qt.m4 index 6a455f9134..607fc6455e 100644 --- a/config/qt.m4 +++ b/config/qt.m4 @@ -28,10 +28,10 @@ AC_DEFUN([QT_CHECK_COMPILE], qt_guilibs="'-lQtCore -lQtGui' '-lQtCore4 -lQtGui4'" if test $USE_QT6 = "yes" ; then qt_corelibs="-lQt6Core" - qt_guilibs="-lQt6Core -lQt6Concurrent -lQt6Gui -lQt6Svg -lQt6Widgets" + qt_guilibs="-lQt6Core -lQt6Concurrent -lQt6Gui -lQt6Svg -lQt6Xml -lQt6Widgets" else qt_corelibs="-lQt5Core" - qt_guilibs="-lQt5Core -lQt5Concurrent -lQt5Gui -lQt5Svg -lQt5Widgets" + qt_guilibs="-lQt5Core -lQt5Concurrent -lQt5Gui -lQt5Svg -lQt5Xml -lQt5Widgets" fi for libname in $qt_corelibs '-framework QtCore' do @@ -43,8 +43,8 @@ AC_DEFUN([QT_CHECK_COMPILE], done qt_cv_libname= for libname in $qt_guilibs \ - '-framework QtCore -framework QtConcurrent -framework QtSvg -framework QtWidgets -framework QtMacExtras -framework QtGui'\ - '-framework QtCore -framework QtConcurrent -framework QtSvg -framework QtSvgWidgets -framework QtWidgets -framework QtGui'\ + '-framework QtCore -framework QtConcurrent -framework QtSvg -framework QtXml -framework QtWidgets -framework QtMacExtras -framework QtGui'\ + '-framework QtCore -framework QtConcurrent -framework QtSvg -framework QtSvgWidgets -framework QtXml -framework QtWidgets -framework QtGui'\ '-framework QtCore -framework QtGui' do QT_TRY_LINK($libname) @@ -264,7 +264,7 @@ AC_DEFUN([QT_DO_PKG_CONFIG], export PKG_CONFIG_PATH fi qt_corelibs="Qt5Core" - qt_guilibs="Qt5Core Qt5Concurrent Qt5Gui Qt5Svg Qt5Widgets" + qt_guilibs="Qt5Core Qt5Concurrent Qt5Gui Qt5Svg Qt5Widgets Qt5Xml" lyx_use_x11extras=false PKG_CHECK_EXISTS(Qt5X11Extras, [lyx_use_x11extras=true], []) if $lyx_use_x11extras; then @@ -339,7 +339,7 @@ AC_DEFUN([QT_DO_MANUAL_CONFIG], QT_CORE_LDFLAGS= if test -n "$qt_cv_includes"; then QT_INCLUDES="-I$qt_cv_includes" - for i in Qt QtCore QtGui QtWidgets QtSvg QtConcurrent QtSvgWidgets QtMacExtras; do + for i in Qt QtCore QtGui QtWidgets QtSvg QtConcurrent QtSvgWidgets QtXml QtMacExtras; do QT_INCLUDES="$QT_INCLUDES -I$qt_cv_includes/$i" if test "$lyx_use_packaging" = "macosx" ; then QT_INCLUDES="$QT_INCLUDES -I$qt_cv_libraries/${i}.framework/Headers" @@ -435,6 +435,8 @@ qtHaveModule(concurrent) {QT += concurrent} else {MISSING += concurrent} qtHaveModule(gui) {QT += gui} else {MISSING += gui} qtHaveModule(gui-private) {QT += gui-private} else {MISSING += gui-private} qtHaveModule(svg) {QT += svg} else {MISSING += svg} +qtHaveModule(svgwidgets) {QT += svgwidgets} else {MISSING += svgwidgets} +qtHaveModule(xml) {QT += xml} else {MISSING += xml} qtHaveModule(widgets) {QT += widgets} else {MISSING += widgets} EOF2 if test "$qt_major" = 6; then diff --git a/src/mathed/InsetMathBox.cpp b/src/mathed/InsetMathBox.cpp index 6feddf9cdd..09a0a0f351 100644 --- a/src/mathed/InsetMathBox.cpp +++ b/src/mathed/InsetMathBox.cpp @@ -28,6 +28,10 @@ #include #include +#include +#include +#include "support/qstring_helpers.h" + using namespace lyx::support; namespace lyx { @@ -62,6 +66,10 @@ namespace { void splitAndWrapInMText(MathMLStream & ms, MathData const & cell, const std::string & attributes) { + // The goal of this function is to take an XML fragment and wrap + // anything that is outside of any tag in tags, + // then wrap the whole thing in an tag with attributes + // First, generate the inset into a string of its own. docstring inset_contents; { @@ -74,53 +82,46 @@ void splitAndWrapInMText(MathMLStream & ms, MathData const & cell, inset_contents = ostmp.str(); } - // 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 (std::size_t 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"); + // We use the QT XML library. It's easier if we deal with an XML "document" + // rather than "fragment", so we wrap it in a fake root node (which we will + // remove at the end). + docstring inset_contents_xml = "" + inset_contents + ""; + + // Parse the XML into a DOM + QDomDocument xml; + xml.setContent(toqstr(inset_contents_xml)); + + QDomElement docElem = xml.documentElement(); + + // Iterate through the children of our fake root element. + QDomNode n = docElem.firstChild(); + while (!n.isNull()) { + // try to convert the child into a text element + // (i.e. some text that is outside of an XML tag) + QDomText text = n.toText(); + if (!text.isNull()) { + // if the result is not null, then the child was indeed + // bare text, so we need to wrap it in mtext tags + // make an mtext element + QDomElement wrapper = xml.createElement(toqstr(ms.namespacedTag("mtext"))); + // put the mtext element in the document right before the text + docElem.insertBefore(wrapper,n); + // move the text node inside the mtext element (this has the side + // effect of removing it from where it was as a child of the root) + wrapper.appendChild(n); + n = wrapper.nextSibling(); + } else { + // if the text is null, then we have something besides a text + // element (i.e. a tag), so we don't need to do anything and just + // move onto the next child + n = n.nextSibling(); + } + } + + ms << MTag("mrow", attributes); + docstring interior = qstring_to_ucs4(xml.toString(-1)); + ms << interior.substr(6,interior.length()-13); // chop off the initial and final tags + ms << ETag("mrow"); } } -- 2.39.5