sw/qa/extras/ooxmlexport/data/tdf136929_framesOfParagraph.odt |binary
 sw/qa/extras/ooxmlexport/ooxmlexport15.cxx                    |    7 ++
 sw/source/filter/ww8/docxattributeoutput.cxx                  |   27 +++++++---
 sw/source/filter/ww8/docxattributeoutput.hxx                  |    2 
 4 files changed, 29 insertions(+), 7 deletions(-)

New commits:
commit 7d90b50285f294a3c9cce0b22399fefe3ab46ee5
Author:     Justin Luth <justin.l...@collabora.com>
AuthorDate: Thu Dec 10 11:29:53 2020 +0300
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Dec 14 11:23:31 2020 +0100

    tdf#136929 docx export: keep frame with paragraph
    
    EndParagraph was checking if any frames were to be
    attached. Well, startParagraph can occur multiple
    times before endParagraph, so the frames can be
    attached to the wrong paragraph. In this case,
    it was moving the text-body frame into the footer.
    
    So make a stack of these things, so that each
    paragraph can keep track of it's own setting.
    
    RTF can have endParagraph without startParagraph.
    Although that doesn't seem to apply
    in this DOCX-only context, just to be safe
    I'm assuming that it could in theory happen
    as well with a DOCX, and so never assume
    that the stack exists.
    
    Based on a code read, (and then a
    confirming unit test,) things seem to be
    complicated by multi-levels of textboxes
    that need to be squished.
    
    The for loop with a changing upper end
    really threw me for a loop, so I'm
    clearly documenting that.
    
    Change-Id: I1060736c0a2174af125d853ff7d72265e000c8de
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107516
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <justin_l...@sil.org>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit 3fd156419654ba5e2f248357a2eed5eeaad04548)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107552
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf136929_framesOfParagraph.odt 
b/sw/qa/extras/ooxmlexport/data/tdf136929_framesOfParagraph.odt
new file mode 100644
index 000000000000..918b24f670db
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/tdf136929_framesOfParagraph.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx
index b9ae69668c6d..20f9c75a311c 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx
@@ -458,6 +458,13 @@ DECLARE_OOXMLEXPORT_TEST(testTdf135216_evenOddFooter, 
"tdf135216_evenOddFooter.o
     getParagraph(2, "2");
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf136929_framesOfParagraph, 
"tdf136929_framesOfParagraph.odt")
+{
+    // Before this fix, the image was placed in the footer instead of in the 
text body - messing everything up.
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of Pages", 5, getPages() );
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Header2 text", OUString("* | *"), 
parseDump("/root/page[4]/footer/txt"));
+}
+
 DECLARE_OOXMLEXPORT_TEST(testTdf136589_paraHadField, 
"tdf136589_paraHadField.docx")
 {
     // The section break should not add an additional CR - which equals an 
empty page two.
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 0ae46d86525e..534ba9b4f8bf 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -383,6 +383,12 @@ static void 
checkAndWriteFloatingTables(DocxAttributeOutput& rDocxAttributeOutpu
 
 void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t 
pTextNodeInfo )
 {
+    // Paragraphs (in headers/footers/comments/frames etc) can start before 
another finishes.
+    // So a stack is needed to keep track of each paragraph's status 
separately.
+    // Complication: Word can't handle nested text boxes, so those need to be 
collected together.
+    if ( !m_aFramesOfParagraph.size() || !m_nTextFrameLevel )
+        m_aFramesOfParagraph.push(std::vector<ww8::Frame>());
+
     // look ahead for floating tables that were put into a frame during import
     // floating tables in shapes are not supported: exclude this case
     if (!pTextNodeInfo && !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen())
@@ -647,10 +653,13 @@ void DocxAttributeOutput::EndParagraph( 
ww8::WW8TableNodeInfoInner::Pointer_t pT
 
         assert(!m_pPostponedCustomShape);
         m_pPostponedCustomShape.reset(new std::vector<PostponedDrawing>);
-        for (size_t nIndex = 0; nIndex < m_aFramesOfParagraph.size(); ++nIndex)
+
+        // The for loop can change the size of m_aFramesOfParagraph, so the 
max size cannot be set in stone before the loop.
+        size_t nFrames = m_aFramesOfParagraph.size() ? 
m_aFramesOfParagraph.top().size() : 0;
+        for (size_t nIndex = 0; nIndex < nFrames; ++nIndex)
         {
             m_bParagraphFrameOpen = true;
-            ww8::Frame aFrame = m_aFramesOfParagraph[nIndex];
+            ww8::Frame aFrame = m_aFramesOfParagraph.top()[nIndex];
             const SwFrameFormat& rFrameFormat = aFrame.GetFrameFormat();
 
             if (!TextBoxIsFramePr(rFrameFormat) || m_bWritingHeaderFooter)
@@ -714,6 +723,8 @@ void DocxAttributeOutput::EndParagraph( 
ww8::WW8TableNodeInfoInner::Pointer_t pT
                 std::shared_ptr<ww8::Frame> pFramePr = 
std::make_shared<ww8::Frame>(aFrame);
                 aFramePrTextbox.push_back(pFramePr);
             }
+
+            nFrames = m_aFramesOfParagraph.size() ? 
m_aFramesOfParagraph.top().size() : 0;
         }
         if (!m_pPostponedCustomShape->empty())
         {
@@ -723,7 +734,8 @@ void DocxAttributeOutput::EndParagraph( 
ww8::WW8TableNodeInfoInner::Pointer_t pT
         }
         m_pPostponedCustomShape.reset();
 
-        m_aFramesOfParagraph.clear();
+        if ( m_aFramesOfParagraph.size() )
+            m_aFramesOfParagraph.top().clear();
 
         if (!pTextNodeInfoInner)
         {
@@ -733,6 +745,8 @@ void DocxAttributeOutput::EndParagraph( 
ww8::WW8TableNodeInfoInner::Pointer_t pT
     }
 
     --m_nTextFrameLevel;
+    if ( m_aFramesOfParagraph.size() && !m_nTextFrameLevel )
+        m_aFramesOfParagraph.pop();
 
     /* If m_nHyperLinkCount > 0 that means hyperlink tag is not yet closed.
      * This is due to nested hyperlink tags. So close it before end of 
paragraph.
@@ -6040,10 +6054,10 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const 
ww8::Frame &rFrame, const P
                 // The frame output is postponed to the end of the anchor 
paragraph
                 bool bDuplicate = false;
                 const OUString& rName = rFrame.GetFrameFormat().GetName();
-                unsigned nSize = m_aFramesOfParagraph.size();
+                unsigned nSize = m_aFramesOfParagraph.size() ? 
m_aFramesOfParagraph.top().size() : 0;
                 for( unsigned nIndex = 0; nIndex < nSize; ++nIndex )
                 {
-                    const OUString& rNameExisting = 
m_aFramesOfParagraph[nIndex].GetFrameFormat().GetName();
+                    const OUString& rNameExisting = 
m_aFramesOfParagraph.top()[nIndex].GetFrameFormat().GetName();
 
                     if (!rName.isEmpty() && !rNameExisting.isEmpty())
                     {
@@ -6055,7 +6069,8 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const 
ww8::Frame &rFrame, const P
                 if( !bDuplicate )
                 {
                     m_bPostponedProcessingFly = true ;
-                    m_aFramesOfParagraph.emplace_back(rFrame);
+                    if ( m_aFramesOfParagraph.size() )
+                        m_aFramesOfParagraph.top().emplace_back(rFrame);
                 }
             }
             break;
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx 
b/sw/source/filter/ww8/docxattributeoutput.hxx
index 349cab0cb310..cfc6eae89f12 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -854,7 +854,7 @@ private:
     // This paragraph must end with page break
     bool m_bPageBreakAfter = false;
 
-    std::vector<ww8::Frame> m_aFramesOfParagraph;
+    std::stack< std::vector<ww8::Frame> > m_aFramesOfParagraph;
     o3tl::sorted_vector<const SwFrameFormat*> m_aFloatingTablesOfParagraph;
     sal_Int32 m_nTextFrameLevel;
 
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to