[Libreoffice-commits] core.git: sw/qa sw/source
Attila Bakos (NISZ) (via logerrit)
logerrit at kemper.freedesktop.org
Thu Jul 1 10:48:09 UTC 2021
sw/qa/extras/layout/data/Tdf121509.odt |binary
sw/qa/extras/layout/layout2.cxx | 58 +++++++++++++++++++++++
sw/source/filter/ww8/docxattributeoutput.cxx | 68 ++++++++++++++++++++++++++-
sw/source/filter/ww8/docxattributeoutput.hxx | 9 +++
4 files changed, 134 insertions(+), 1 deletion(-)
New commits:
commit 35732c84b05e4f6e50349796636beb01f2a09907
Author: Attila Bakos (NISZ) <bakos.attilakaroly at nisz.hu>
AuthorDate: Mon Jun 14 15:24:06 2021 +0200
Commit: László Németh <nemeth at numbertext.org>
CommitDate: Thu Jul 1 12:47:35 2021 +0200
tdf#121509 DOCX export: fix corrupt shape anchoring in textbox
MSO doesn't support shapes anchored to character in a textbox.
Convert these shapes by re-anchoring them to the anchor
point of the textbox (also recalculating their positions in
simple cases), so Word can now open the exported document.
Change-Id: I28b244975981d69c50e5d4a46249918af089bae5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117163
Tested-by: László Németh <nemeth at numbertext.org>
Reviewed-by: László Németh <nemeth at numbertext.org>
diff --git a/sw/qa/extras/layout/data/Tdf121509.odt b/sw/qa/extras/layout/data/Tdf121509.odt
new file mode 100644
index 000000000000..856f60c88764
Binary files /dev/null and b/sw/qa/extras/layout/data/Tdf121509.odt differ
diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx
index 72cdc908b6ca..1db5f1e69214 100644
--- a/sw/qa/extras/layout/layout2.cxx
+++ b/sw/qa/extras/layout/layout2.cxx
@@ -49,6 +49,9 @@
#include <svx/svdpage.hxx>
#include <svx/svdotext.hxx>
#include <dcontact.hxx>
+#include <frameformats.hxx>
+#include <fmtcntnt.hxx>
+#include <unotextrange.hxx>
constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/extras/layout/data/";
@@ -1442,6 +1445,61 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf127118)
assertXPath(pXmlDoc, "/root/page[2]/body/tab/row[1]/cell[1]/txt[1]", "WritingMode", "VertBTLR");
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf121509)
+{
+ auto pDoc = createSwDoc(DATA_DIRECTORY, "Tdf121509.odt");
+ CPPUNIT_ASSERT(pDoc);
+
+ // Get all shape/frame formats
+ auto vFrameFormats = pDoc->GetSpzFrameFormats();
+ // Get the textbox
+ auto xTextFrame = SwTextBoxHelper::getUnoTextFrame(getShape(1));
+ // Get The triangle
+ auto pTriangleShapeFormat = vFrameFormats->GetFormat(2);
+ CPPUNIT_ASSERT(xTextFrame);
+ CPPUNIT_ASSERT(pTriangleShapeFormat);
+
+ // Get the position inside the textbox
+ auto xTextContentStart = xTextFrame->getText()->getStart();
+ SwUnoInternalPaM aCursor(*pDoc);
+ CPPUNIT_ASSERT(sw::XTextRangeToSwPaM(aCursor, xTextContentStart));
+
+ // Put the triangle into the textbox
+ SwFormatAnchor aNewAnch(pTriangleShapeFormat->GetAnchor());
+ aNewAnch.SetAnchor(aCursor.Start());
+ CPPUNIT_ASSERT(pTriangleShapeFormat->SetFormatAttr(aNewAnch));
+
+ // Reload (docx)
+ auto aTemp = utl::TempFile();
+ save("Office Open XML Text", aTemp);
+
+ // The second part: check if the reloaded doc has flys inside a fly
+ uno::Reference<lang::XComponent> xComponent
+ = loadFromDesktop(aTemp.GetURL(), "com.sun.star.text.TextDocument");
+ uno::Reference<text::XTextDocument> xTextDoc(xComponent, uno::UNO_QUERY);
+ auto pTextDoc = dynamic_cast<SwXTextDocument*>(xTextDoc.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ auto pSecondDoc = pTextDoc->GetDocShell()->GetDoc();
+ auto pSecondFormats = pSecondDoc->GetSpzFrameFormats();
+
+ bool bFlyInFlyFound = false;
+ for (auto secondformat : *pSecondFormats)
+ {
+ auto& pNd = secondformat->GetAnchor().GetContentAnchor()->nNode.GetNode();
+ if (pNd.FindFlyStartNode())
+ {
+ // So there is a fly inside another -> problem.
+ bFlyInFlyFound = true;
+ break;
+ }
+ }
+ // Drop the tempfile
+ aTemp.CloseStream();
+
+ // With the fix this cannot be true, if it is, that means Word unable to read the file..
+ CPPUNIT_ASSERT_MESSAGE("Corrupt exported docx file!", !bFlyInFlyFound);
+}
+
CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf134685)
{
createSwDoc(DATA_DIRECTORY, "tdf134685.docx");
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 7d185f5ce9c0..19dc42aa119c 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -6082,7 +6082,7 @@ void DocxAttributeOutput::WritePostponedDMLDrawing()
m_pPostponedOLEs = std::move(pPostponedOLEs);
}
-void DocxAttributeOutput::OutputFlyFrame_Impl( const ww8::Frame &rFrame, const Point& /*rNdTopLeft*/ )
+void DocxAttributeOutput::WriteFlyFrame(const ww8::Frame& rFrame)
{
m_pSerializer->mark(Tag_OutputFlyFrame);
@@ -6254,6 +6254,71 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const ww8::Frame &rFrame, const P
m_pSerializer->mergeTopMarks(Tag_OutputFlyFrame);
}
+void DocxAttributeOutput::OutputFlyFrame_Impl(const ww8::Frame& rFrame, const Point& /*rNdTopLeft*/)
+{
+ /// The old OutputFlyFrame_Impl() moved to WriteFlyFrame().
+ /// Now if a frame anchored inside another frame, it will
+ /// not be exported immediately, because OOXML does not
+ /// support that feature, instead it postponed and exported
+ /// later when the original shape closed.
+
+ if (rFrame.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR
+ || rFrame.IsInline())
+ {
+ m_nEmbedFlyLevel++;
+ WriteFlyFrame(rFrame);
+ m_nEmbedFlyLevel--;
+ return;
+ }
+
+ if (m_nEmbedFlyLevel == 0)
+ {
+ if (m_vPostponedFlys.empty())
+ {
+ m_nEmbedFlyLevel++;
+ WriteFlyFrame(rFrame);
+ m_nEmbedFlyLevel--;
+ }
+ else
+ for (auto it = m_vPostponedFlys.begin(); it != m_vPostponedFlys.end();)
+ {
+ m_nEmbedFlyLevel++;
+ WriteFlyFrame(*it);
+ it = m_vPostponedFlys.erase(it);
+ m_nEmbedFlyLevel--;
+ }
+ }
+ else
+ {
+ bool bFound = false;
+ for (const auto& i : m_vPostponedFlys)
+ {
+ if (i.RefersToSameFrameAs(rFrame))
+ {
+ bFound = true;
+ break;
+ }
+ }
+ if (!bFound)
+ {
+ if (auto pParentFly = rFrame.GetContentNode()->GetFlyFormat())
+ {
+ auto aHori(rFrame.GetFrameFormat().GetHoriOrient());
+ aHori.SetPos(aHori.GetPos() + pParentFly->GetHoriOrient().GetPos());
+ auto aVori(rFrame.GetFrameFormat().GetVertOrient());
+ aVori.SetPos(aVori.GetPos() + pParentFly->GetVertOrient().GetPos());
+
+ const_cast<SwFrameFormat&>(rFrame.GetFrameFormat()).SetFormatAttr(aHori);
+ const_cast<SwFrameFormat&>(rFrame.GetFrameFormat()).SetFormatAttr(aVori);
+ const_cast<SwFrameFormat&>(rFrame.GetFrameFormat()).SetFormatAttr(pParentFly->GetAnchor());
+
+ m_vPostponedFlys.push_back(rFrame);
+ }
+
+ }
+ }
+}
+
void DocxAttributeOutput::WriteOutliner(const OutlinerParaObject& rParaObj)
{
const EditTextObject& rEditObj = rParaObj.GetTextObject();
@@ -9993,6 +10058,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, const FSHelperPtr
m_sFieldBkm( ),
m_nNextBookmarkId( 0 ),
m_nNextAnnotationMarkId( 0 ),
+ m_nEmbedFlyLevel(0),
m_pCurrentFrame( nullptr ),
m_bParagraphOpened( false ),
m_bParagraphFrameOpen( false ),
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index b0688183ab69..7f880cc506c4 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -718,6 +718,7 @@ private:
void WritePostponedOLE();
void WritePostponedDMLDrawing();
void WritePostponedCustomShape();
+ void WriteFlyFrame(const ww8::Frame& rFrame);
void WriteSdtBlock(sal_Int32& nSdtPrToken,
rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren,
@@ -802,6 +803,14 @@ private:
OUString m_sRawText;
+ /// The first frame (anchored to the main text) is 0.
+ /// The second frame what is anchored to the previous in, is 1
+ /// The third anchored inside the second is the 2 etc.
+ sal_uInt32 m_nEmbedFlyLevel;
+
+ /// Stores the flys what are anchored inside a fly
+ std::vector<ww8::Frame> m_vPostponedFlys;
+
/// Bookmarks to output
std::vector<OUString> m_rBookmarksStart;
std::vector<OUString> m_rBookmarksEnd;
More information about the Libreoffice-commits
mailing list