diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index a9b186b1a6..3718bd4a98 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -3673,6 +3673,7 @@ std::tuple, std::vector, std::vectorstartDivision(false); std::vector delayedChars; // When a font tag ends with a space, output it after the closing font tag. // This requires to store delayed characters at some point. @@ -3696,8 +3697,8 @@ std::tuple, std::vector, std::vectorlyxCode() == NEWLINE_CODE) { if (!ignore_fonts_i) xs->closeFontTags(); @@ -3705,11 +3706,14 @@ std::tuple, std::vector, std::vectorendDivision(); + // Create a new XMLStream for the new paragraph, completely independent of the previous one. This implies // that the string stream must be reset. os.str(from_ascii("")); delete xs; xs = new XMLStream(os); + xs->startDivision(false); // Restore the fonts for the new paragraph, so that the right tags are opened for the new entry. if (!ignore_fonts_i) { @@ -3744,11 +3748,12 @@ std::tuple, std::vector, std::vector::const_iterator sen = tagsToOpen.end(); for (; sit != sen; ++sit) *xs << *sit; - - tagsToClose.clear(); - tagsToOpen.clear(); } + // The font tags are no longer useful; free their memory right now. + tagsToClose.clear(); + tagsToOpen.clear(); + // Finally, write the next character or inset. if (Inset const * inset = getInset(i)) { bool inset_is_argument_elsewhere = getInset(i)->asInsetArgument() && @@ -3781,12 +3786,21 @@ std::tuple, std::vector, std::vectorcloseFontTags(); + // Close the potentially remaining tags, like pending font tags. + // There is no need to check for ignore_fonts, as these tags won't be + // inserted in the stack in the first place if ignore_fonts is false. + xs->endDivision(); + // Deal with the delayed characters *after* closing font tags. if (!delayedChars.empty()) { for (const docstring &c: delayedChars) diff --git a/src/xml.cpp b/src/xml.cpp index 53ccb8a8c8..5b81024336 100644 --- a/src/xml.cpp +++ b/src/xml.cpp @@ -287,6 +287,16 @@ XMLStream &XMLStream::operator<<(docstring const &d) } +XMLStream &XMLStream::operator<<(xml::NullTag const &) +{ + is_last_tag_cr_ = false; + clearTagDeque(); + // Don't output anything to os_, by definition of a NullTag (as opposed to text output). + escape_ = ESCAPE_ALL; + return *this; +} + + XMLStream &XMLStream::operator<<(const char *s) { is_last_tag_cr_ = false; diff --git a/src/xml.h b/src/xml.h index 03710c1c72..346e42d78c 100644 --- a/src/xml.h +++ b/src/xml.h @@ -31,6 +31,7 @@ namespace xml { struct StartTag; struct EndTag; struct CompTag; +struct NullTag; struct ParTag; struct FontTag; struct CR; @@ -67,6 +68,8 @@ public: /// XMLStream & operator<<(char); /// + XMLStream & operator<<(xml::NullTag const &); + /// XMLStream & operator<<(xml::StartTag const &); /// XMLStream & operator<<(xml::EndTag const &); @@ -274,6 +277,16 @@ struct ParTag : public StartTag }; +/// A special tag that doesn't produce any XML output, but makes the XMLStream behave as it it output some text. +struct NullTag : public StartTag +{ + /// + NullTag(): StartTag("NULLTAG", from_utf8(""), true) {} + /// + ~NullTag() override = default; +}; + + /// enum FontTypes { // ranges