include/svtools/HtmlWriter.hxx | 3 svtools/qa/unit/testHtmlWriter.cxx | 6 svtools/source/svhtml/HtmlWriter.cxx | 25 +- sw/qa/extras/htmlexport/data/image_anchored_to_paragraph_no_wrap.fodt | 20 + sw/qa/extras/htmlexport/htmlexport.cxx | 18 + sw/source/filter/html/htmlflywriter.cxx | 112 +++++----- 6 files changed, 115 insertions(+), 69 deletions(-)
New commits: commit b0391cf000850b28546f0d21f194060ed86507c2 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Mon Nov 27 16:01:11 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Nov 29 10:47:34 2023 +0300 Don't emit 'br clear=...' for graphics wrap in ReqIF export Change-Id: I7684c78c9b98fe63c2281bf3b2a2186d125e0ba4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159994 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/htmlexport/data/image_anchored_to_paragraph_no_wrap.fodt b/sw/qa/extras/htmlexport/data/image_anchored_to_paragraph_no_wrap.fodt new file mode 100644 index 000000000000..f1080724307e --- /dev/null +++ b/sw/qa/extras/htmlexport/data/image_anchored_to_paragraph_no_wrap.fodt @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:automatic-styles> + <style:style style:name="fr1" style:family="graphic" style:parent-style-name="OLE"> + <style:graphic-properties style:wrap="none"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="paragraph" svg:width="17cm" svg:height="13cm"><draw:image draw:mime-type="image/svg+xml"> + <office:binary-data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0 + cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDIw + IDIwIiBzdHJva2U9ImJsYWNrIj4KPHBhdGggZD0iTTEsMUwxOSwxOSIvPgo8L3N2Zz4= + </office:binary-data> + </draw:image> + </draw:frame></text:p> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index d72e2b1daf9e..662dc12a5a0b 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -2997,6 +2997,24 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_ExportFormulasAsPDF) xTypeDetection->queryTypeByDescriptor(descr, true)); } +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_NoBrClearForImageWrap) +{ + // Given a document with a paragraph-anchored image with "none" wrap: + createSwDoc("image_anchored_to_paragraph_no_wrap.fodt"); + // When exporting to reqif: + ExportToReqif(); + // Make sure that there's no 'br' elements in the 'object' (used to represent the wrapping + // in HTML export, using 'clear' attribute): + SvMemoryStream aStream; + WrapReqifFromTempFile(aStream); + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + CPPUNIT_ASSERT(pXmlDoc); + assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object"); + assertXPath(pXmlDoc, + "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object/reqif-xhtml:br", + 0); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/html/htmlflywriter.cxx b/sw/source/filter/html/htmlflywriter.cxx index b58d3d9f6c44..624d992fb273 100644 --- a/sw/source/filter/html/htmlflywriter.cxx +++ b/sw/source/filter/html/htmlflywriter.cxx @@ -723,68 +723,71 @@ OString SwHTMLWriter::OutFrameFormatOptions( const SwFrameFormat &rFrameFormat, sOut.setLength(0); } - // Insert wrap for graphics that are anchored to a paragraph as - // <BR CLEAR=...> in the string - const SwFormatSurround* pSurround; - if( (nFrameOpts & HtmlFrmOpts::BrClear) && - ((RndStdIds::FLY_AT_PARA == rFrameFormat.GetAnchor().GetAnchorId()) || - (RndStdIds::FLY_AT_CHAR == rFrameFormat.GetAnchor().GetAnchorId())) && - (pSurround = rItemSet.GetItemIfSet( RES_SURROUND )) ) - { - sal_Int16 eHoriOri = rFrameFormat.GetHoriOrient().GetHoriOrient(); - pStr = nullptr; - css::text::WrapTextMode eSurround = pSurround->GetSurround(); - bool bAnchorOnly = pSurround->IsAnchorOnly(); - switch( eHoriOri ) + if (!mbReqIF) + { + // Insert wrap for graphics that are anchored to a paragraph as + // <BR CLEAR=...> in the string + const SwFormatSurround* pSurround; + if( (nFrameOpts & HtmlFrmOpts::BrClear) && + ((RndStdIds::FLY_AT_PARA == rFrameFormat.GetAnchor().GetAnchorId()) || + (RndStdIds::FLY_AT_CHAR == rFrameFormat.GetAnchor().GetAnchorId())) && + (pSurround = rItemSet.GetItemIfSet( RES_SURROUND )) ) { - case text::HoriOrientation::RIGHT: + sal_Int16 eHoriOri = rFrameFormat.GetHoriOrient().GetHoriOrient(); + pStr = nullptr; + css::text::WrapTextMode eSurround = pSurround->GetSurround(); + bool bAnchorOnly = pSurround->IsAnchorOnly(); + switch( eHoriOri ) { - switch( eSurround ) + case text::HoriOrientation::RIGHT: { - case css::text::WrapTextMode_NONE: - case css::text::WrapTextMode_RIGHT: - pStr = OOO_STRING_SVTOOLS_HTML_AL_right; - break; - case css::text::WrapTextMode_LEFT: - case css::text::WrapTextMode_PARALLEL: - if( bAnchorOnly ) - m_bClearRight = true; - break; - default: - ; + switch( eSurround ) + { + case css::text::WrapTextMode_NONE: + case css::text::WrapTextMode_RIGHT: + pStr = OOO_STRING_SVTOOLS_HTML_AL_right; + break; + case css::text::WrapTextMode_LEFT: + case css::text::WrapTextMode_PARALLEL: + if( bAnchorOnly ) + m_bClearRight = true; + break; + default: + ; + } } - } - break; + break; - default: - // If a frame is centered, it gets left aligned. This - // should be taken into account here, too. - { - switch( eSurround ) + default: + // If a frame is centered, it gets left aligned. This + // should be taken into account here, too. { - case css::text::WrapTextMode_NONE: - case css::text::WrapTextMode_LEFT: - pStr = OOO_STRING_SVTOOLS_HTML_AL_left; - break; - case css::text::WrapTextMode_RIGHT: - case css::text::WrapTextMode_PARALLEL: - if( bAnchorOnly ) - m_bClearLeft = true; - break; - default: - ; + switch( eSurround ) + { + case css::text::WrapTextMode_NONE: + case css::text::WrapTextMode_LEFT: + pStr = OOO_STRING_SVTOOLS_HTML_AL_left; + break; + case css::text::WrapTextMode_RIGHT: + case css::text::WrapTextMode_PARALLEL: + if( bAnchorOnly ) + m_bClearLeft = true; + break; + default: + ; + } } - } - break; + break; - } + } - if( pStr ) - { - sOut.append("<" OOO_STRING_SVTOOLS_HTML_linebreak - " " OOO_STRING_SVTOOLS_HTML_O_clear - "=\"" + OString::Concat(pStr) + "\">"); - sRetEndTags = sOut.makeStringAndClear(); + if( pStr ) + { + sOut.append("<" OOO_STRING_SVTOOLS_HTML_linebreak + " " OOO_STRING_SVTOOLS_HTML_O_clear + "=\"" + OString::Concat(pStr) + "\">"); + sRetEndTags = sOut.makeStringAndClear(); + } } } return sRetEndTags; @@ -1034,6 +1037,9 @@ void SwHTMLWriter::writeFrameFormatOptions(HtmlWriter& aHtml, const SwFrameForma } } + if (mbReqIF) + return; + // Insert wrap for graphics that are anchored to a paragraph as // <BR CLEAR=...> in the string commit 2c315ab60701519a3524c5b3f636d09512b42cf7 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Fri Nov 24 18:16:11 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Nov 29 09:23:23 2023 +0300 Fix HtmlWriter::characters This method may be called after an end(), and then it shouldn't try to close a tag again. Also in this case the characters shouldn't be considered in the next start()/characters()/end() run. Clarify the meaning of the previous mbElementOpen, by renaming it to mbOpeningTagOpen. The old mbCharactersWritten flag was redundant. Change-Id: Ie0ac6ddd88be774853a1fc152742b51793af798b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159932 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/include/svtools/HtmlWriter.hxx b/include/svtools/HtmlWriter.hxx index 21ccad0cd96d..9fe66a7d9ad2 100644 --- a/include/svtools/HtmlWriter.hxx +++ b/include/svtools/HtmlWriter.hxx @@ -24,8 +24,7 @@ private: SvStream& mrStream; - bool mbElementOpen; - bool mbCharactersWritten; + bool mbOpeningTagOpen = false; bool mbPrettyPrint; /// XML namespace, in case of XHTML. OString maNamespace; diff --git a/svtools/qa/unit/testHtmlWriter.cxx b/svtools/qa/unit/testHtmlWriter.cxx index 702bf64464ab..e4d31a2da46e 100644 --- a/svtools/qa/unit/testHtmlWriter.cxx +++ b/svtools/qa/unit/testHtmlWriter.cxx @@ -175,10 +175,14 @@ CPPUNIT_TEST_FIXTURE(Test, testCharacters) aHtml.start("abc"); aHtml.characters("hello"); aHtml.end(); + aHtml.characters(" "); // Should not try to close a not opened tag + aHtml.start("abc"); + aHtml.characters("world"); // Should close opening tag + aHtml.end(); OString aString = extractFromStream(aStream); - CPPUNIT_ASSERT_EQUAL(OString("<abc>hello</abc>"), aString); + CPPUNIT_ASSERT_EQUAL(OString("<abc>hello</abc> <abc>world</abc>"), aString); } CPPUNIT_TEST_FIXTURE(Test, testExactElementEnd) diff --git a/svtools/source/svhtml/HtmlWriter.cxx b/svtools/source/svhtml/HtmlWriter.cxx index 8f99e3b29110..bbb63ba98051 100644 --- a/svtools/source/svhtml/HtmlWriter.cxx +++ b/svtools/source/svhtml/HtmlWriter.cxx @@ -15,8 +15,6 @@ HtmlWriter::HtmlWriter(SvStream& rStream, std::string_view rNamespace) : mrStream(rStream), - mbElementOpen(false), - mbCharactersWritten(false), mbPrettyPrint(true) { if (!rNamespace.empty()) @@ -36,7 +34,7 @@ void HtmlWriter::prettyPrint(bool b) void HtmlWriter::start(const OString& aElement) { - if (mbElementOpen) + if (mbOpeningTagOpen) { mrStream.WriteChar('>'); if (mbPrettyPrint) @@ -54,7 +52,7 @@ void HtmlWriter::start(const OString& aElement) mrStream.WriteChar('<'); mrStream.WriteOString(Concat2View(maNamespace + aElement)); - mbElementOpen = true; + mbOpeningTagOpen = true; } void HtmlWriter::single(const OString &aContent) @@ -65,12 +63,12 @@ void HtmlWriter::single(const OString &aContent) void HtmlWriter::endAttribute() { - if (mbElementOpen) + if (mbOpeningTagOpen) { mrStream.WriteCharPtr("/>"); if (mbPrettyPrint) mrStream.WriteCharPtr("\n"); - mbElementOpen = false; + mbOpeningTagOpen = false; } } @@ -92,11 +90,12 @@ bool HtmlWriter::end(const OString& aElement) void HtmlWriter::end() { - if (mbElementOpen && !mbCharactersWritten) + if (mbOpeningTagOpen) { mrStream.WriteCharPtr("/>"); if (mbPrettyPrint) mrStream.WriteCharPtr("\n"); + mbOpeningTagOpen = false; } else { @@ -114,8 +113,6 @@ void HtmlWriter::end() mrStream.WriteCharPtr("\n"); } maElementStack.pop_back(); - mbElementOpen = false; - mbCharactersWritten = false; } void HtmlWriter::writeAttribute(SvStream& rStream, std::string_view aAttribute, sal_Int32 aValue) @@ -134,7 +131,7 @@ void HtmlWriter::writeAttribute(SvStream& rStream, std::string_view aAttribute, void HtmlWriter::attribute(std::string_view aAttribute, std::string_view aValue) { - if (mbElementOpen && !aAttribute.empty() && !aValue.empty()) + if (mbOpeningTagOpen && !aAttribute.empty() && !aValue.empty()) { mrStream.WriteChar(' '); writeAttribute(mrStream, aAttribute, aValue); @@ -158,7 +155,7 @@ void HtmlWriter::attribute(std::string_view aAttribute, std::u16string_view aVal void HtmlWriter::attribute(std::string_view aAttribute) { - if (mbElementOpen && !aAttribute.empty()) + if (mbOpeningTagOpen && !aAttribute.empty()) { mrStream.WriteChar(' '); mrStream.WriteOString(aAttribute); @@ -167,10 +164,12 @@ void HtmlWriter::attribute(std::string_view aAttribute) void HtmlWriter::characters(std::string_view rChars) { - if (!mbCharactersWritten) + if (mbOpeningTagOpen) + { mrStream.WriteCharPtr(">"); + mbOpeningTagOpen = false; + } mrStream.WriteOString(rChars); - mbCharactersWritten = true; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */