summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Luth <justin.luth@collabora.com>2020-12-10 11:29:53 +0300
committerMiklos Vajna <vmiklos@collabora.com>2020-12-11 11:10:27 +0100
commit3fd156419654ba5e2f248357a2eed5eeaad04548 (patch)
treecd672ddd5331bd04e976e21c8c481587218e8fc1
parenta4eec60c388cc65ae0b4c8ea0fd7235f520a749d (diff)
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_luth@sil.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf136929_framesOfParagraph.odtbin0 -> 179339 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport15.cxx7
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx27
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx2
4 files changed, 29 insertions, 7 deletions
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
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf136929_framesOfParagraph.odt
Binary files 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;