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 68688b4ca2288ac815d1dff137177e632bbb5f9f
Author:     Attila Bakos (NISZ) <bakos.attilakar...@nisz.hu>
AuthorDate: Mon Jun 14 15:24:06 2021 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Thu Jul 1 16:06:34 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 <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>
    (cherry picked from commit 35732c84b05e4f6e50349796636beb01f2a09907)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118179
    Tested-by: Jenkins

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 7cbf2a8a0df0..02da5d32096f 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;
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to