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 3fd156419654ba5e2f248357a2eed5eeaad04548 Author: Justin Luth <justin.l...@collabora.com> AuthorDate: Thu Dec 10 11:29:53 2020 +0300 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Dec 11 11:10:27 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> 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 2b1b18aa85f9..e6ea2183d57c 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx @@ -456,6 +456,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 bf25b3111379..e047d6ec54d8 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -380,6 +380,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()) @@ -644,10 +650,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) @@ -711,6 +720,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()) { @@ -720,7 +731,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) { @@ -730,6 +742,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. @@ -6037,10 +6051,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()) { @@ -6052,7 +6066,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