commit fafe3ea5d7be1c06fb734e3bc621c551d617a6f7
Author: Richard Kimberly Heck <[email protected]>
Date: Sun Jun 23 12:37:25 2024 -0400
Fix bug #13069.
Use XML parser to handle <mtext> 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 <iostream>
#include <ostream>
+#include <QtXml/QDomDocument>
+#include <QtXml/QDomElement>
+#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 <mtext></mtext> tags,
+ // then wrap the whole thing in an <mrow></mrow> 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 <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 (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 = "<root>" + inset_contents + "</root>";
+
+ // 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
<root> and final </root> tags
+ ms << ETag("mrow");
}
}
--
lyx-cvs mailing list
[email protected]
http://lists.lyx.org/mailman/listinfo/lyx-cvs