summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf119952_negativeMargins.docxbin0 -> 23533 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport11.cxx83
-rw-r--r--writerfilter/source/dmapper/DomainMapperTableHandler.cxx38
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx63
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.hxx3
-rw-r--r--writerfilter/source/dmapper/PropertyMap.cxx78
-rw-r--r--writerfilter/source/dmapper/PropertyMap.hxx7
7 files changed, 190 insertions, 82 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/tdf119952_negativeMargins.docx b/sw/qa/extras/ooxmlexport/data/tdf119952_negativeMargins.docx
new file mode 100644
index 000000000000..9b5a98d3f1aa
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf119952_negativeMargins.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index d999827899a4..9cfaf5aa6e6c 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -1458,6 +1458,89 @@ DECLARE_OOXMLEXPORT_TEST(testTdf124678_case2, "tdf124678_with_leading_paragraph.
CPPUNIT_ASSERT_EQUAL_MESSAGE("Second page header text", OUString("HEADER"), parseDump("/root/page[2]/header/txt"));
}
+static bool lcl_nearEqual(const sal_Int32 nNumber1, const sal_Int32 nNumber2, sal_Int32 nMaxDiff = 5)
+{
+ return std::abs(nNumber1 - nNumber2) < nMaxDiff;
+}
+
+DECLARE_OOXMLEXPORT_TEST(testTdf119952_negativeMargins, "tdf119952_negativeMargins.docx")
+{
+ // With negative margins (in MS Word) one can set up header (or footer) that overlaps with the body.
+ // LibreOffice unable to display that, so when importing negative margins,
+ // the header (or footer) converted to a flyframe, anchored to the header..
+ // that can overlap with the body, and will appear like in Word.
+ // This conversion modifies the document [i.e. replacing header text with a textbox...]
+ // but its DOCX export looks the same, as the original document in Word, too.
+ xmlDocUniquePtr pDump = parseLayoutDump();
+
+ //Check layout positions / sizes
+ sal_Int32 nLeftHead = getXPath(pDump, "//page[1]/header/infos/bounds", "left").toInt32();
+ sal_Int32 nLeftBody = getXPath(pDump, "//page[1]/body/infos/bounds", "left").toInt32();
+ sal_Int32 nLeftFoot = getXPath(pDump, "//page[1]/footer/infos/bounds", "left").toInt32();
+ sal_Int32 nLeftHFly = getXPath(pDump, "//page[1]/header/txt/anchored/fly/infos/bounds", "left").toInt32();
+ sal_Int32 nLeftFFly = getXPath(pDump, "//page[1]/footer/txt/anchored/fly/infos/bounds", "left").toInt32();
+
+ sal_Int32 nTopHead = getXPath(pDump, "//page[1]/header/infos/bounds", "top").toInt32();
+ sal_Int32 nTopBody = getXPath(pDump, "//page[1]/body/infos/bounds", "top").toInt32();
+ sal_Int32 nTopFoot = getXPath(pDump, "//page[1]/footer/infos/bounds", "top").toInt32();
+ sal_Int32 nTopHFly = getXPath(pDump, "//page[1]/header/txt/anchored/fly/infos/bounds", "top").toInt32();
+ sal_Int32 nTopFFly = getXPath(pDump, "//page[1]/footer/txt/anchored/fly/infos/bounds", "top").toInt32();
+
+ sal_Int32 nHeightHead = getXPath(pDump, "//page[1]/header/infos/bounds", "height").toInt32();
+ sal_Int32 nHeightBody = getXPath(pDump, "//page[1]/body/infos/bounds", "height").toInt32();
+ sal_Int32 nHeightFoot = getXPath(pDump, "//page[1]/footer/infos/bounds", "height").toInt32();
+ sal_Int32 nHeightHFly = getXPath(pDump, "//page[1]/header/txt/anchored/fly/infos/bounds", "height").toInt32();
+ sal_Int32 nHeightFFly = getXPath(pDump, "//page[1]/footer/txt/anchored/fly/infos/bounds", "height").toInt32();
+ sal_Int32 nHeightHFlyBound = getXPath(pDump, "//page[1]/header/infos/prtBounds", "height").toInt32();
+ sal_Int32 nHeightFFlyBound = getXPath(pDump, "//page[1]/footer/infos/prtBounds", "height").toInt32();
+
+ CPPUNIT_ASSERT(lcl_nearEqual(nLeftHead, nLeftBody));
+ CPPUNIT_ASSERT(lcl_nearEqual(nLeftHead, nLeftFoot));
+ CPPUNIT_ASSERT(lcl_nearEqual(nLeftHead, nLeftHFly));
+ CPPUNIT_ASSERT(lcl_nearEqual(nLeftHead, nLeftFFly));
+
+ CPPUNIT_ASSERT(lcl_nearEqual(nTopHead, 851));
+ CPPUNIT_ASSERT(lcl_nearEqual(nTopBody, 1418));
+ CPPUNIT_ASSERT(lcl_nearEqual(nTopFoot, 15875));
+ CPPUNIT_ASSERT(lcl_nearEqual(nTopHFly, 851));
+
+ // this seems to be an import bug
+ if (!mbExported)
+ CPPUNIT_ASSERT(lcl_nearEqual(nTopFFly, 14403));
+
+ CPPUNIT_ASSERT(lcl_nearEqual(nHeightHead, 567));
+ CPPUNIT_ASSERT(lcl_nearEqual(nHeightBody, 14457));
+ CPPUNIT_ASSERT(lcl_nearEqual(nHeightFoot, 680));
+ CPPUNIT_ASSERT(lcl_nearEqual(nHeightHFly, 2152));
+ CPPUNIT_ASSERT(lcl_nearEqual(nHeightFFly, 2152));
+
+ // after export these heights increase to like 567..
+ // not sure if it is an other import, or export bug... or just the result of the modified document
+ if (!mbExported)
+ {
+ CPPUNIT_ASSERT(lcl_nearEqual(nHeightHFlyBound, 57));
+ CPPUNIT_ASSERT(lcl_nearEqual(nHeightFFlyBound, 57));
+ }
+
+ //Check text of header/ footer
+ CPPUNIT_ASSERT_EQUAL(OUString("f1"), getXPath(pDump, "//page[1]/header/txt/anchored/fly/txt[1]/Text", "Portion"));
+ CPPUNIT_ASSERT_EQUAL(OUString(" f8"), getXPath(pDump, "//page[1]/header/txt/anchored/fly/txt[8]/Text", "Portion"));
+ CPPUNIT_ASSERT_EQUAL(OUString(" f8"), getXPath(pDump, "//page[1]/footer/txt/anchored/fly/txt[1]/Text", "Portion"));
+ CPPUNIT_ASSERT_EQUAL(OUString("f1"), getXPath(pDump, "//page[1]/footer/txt/anchored/fly/txt[8]/Text", "Portion"));
+
+ CPPUNIT_ASSERT_EQUAL(OUString("p1"), getXPath(pDump, "//page[2]/header/txt/anchored/fly/txt[1]/Text", "Portion"));
+ CPPUNIT_ASSERT_EQUAL(OUString("p1"), getXPath(pDump, "//page[2]/footer/txt/anchored/fly/txt[1]/Text", "Portion"));
+
+ CPPUNIT_ASSERT_EQUAL(OUString(" aaaa"), getXPath(pDump, "//page[3]/header/txt/anchored/fly/txt[1]/Text", "Portion"));
+ CPPUNIT_ASSERT_EQUAL(OUString(" eeee"), getXPath(pDump, "//page[3]/header/txt/anchored/fly/txt[5]/Text", "Portion"));
+
+ CPPUNIT_ASSERT_EQUAL(OUString("f1 f2 f3 f4 f5 f6 f7 f8"), parseDump("/root/page[1]/header/txt/anchored/fly"));
+ CPPUNIT_ASSERT_EQUAL(OUString(" f8 f7 f6 f5 f4 f3 f2f1"), parseDump("/root/page[1]/footer/txt/anchored/fly"));
+ CPPUNIT_ASSERT_EQUAL(OUString("p1"), parseDump("/root/page[2]/header/txt/anchored/fly"));
+ CPPUNIT_ASSERT_EQUAL(OUString("p1"), parseDump("/root/page[2]/footer/txt/anchored/fly"));
+ CPPUNIT_ASSERT_EQUAL(OUString(" aaaa bbbb cccc dddd eeee"), parseDump("/root/page[3]/header/txt/anchored/fly"));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
index 55c48740f0ec..884a195df75a 100644
--- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
@@ -340,38 +340,6 @@ void lcl_adjustBorderDistance(TableInfo& rInfo, const table::BorderLine2& rLeftB
rInfo.nRightBorderDistance = nActualR;
}
-void lcl_fillEmptyFrameProperties(std::vector<beans::PropertyValue>& rFrameProperties)
-{
- // fill empty frame properties to create an invisible frame around the table:
- // hide frame borders and zero inner and outer frame margins
- beans::PropertyValue aValue;
- aValue.Name = getPropertyName( PROP_ANCHOR_TYPE );
- aValue.Value <<= text::TextContentAnchorType_AS_CHARACTER;
- rFrameProperties.push_back(aValue);
-
- table::BorderLine2 aEmptyBorder;
- static const std::vector<std::u16string_view> aBorderNames
- = { u"TopBorder", u"LeftBorder", u"BottomBorder", u"RightBorder" };
- for (size_t i = 0; i < aBorderNames.size(); ++i)
- {
- beans::PropertyValue aBorderValue;
- aBorderValue.Name = aBorderNames[i];
- aBorderValue.Value <<= aEmptyBorder;
- rFrameProperties.push_back(aBorderValue);
- }
- static const std::vector<std::u16string_view> aMarginNames
- = { u"TopBorderDistance", u"LeftBorderDistance",
- u"BottomBorderDistance", u"RightBorderDistance",
- u"TopMargin", u"LeftMargin", u"BottomMargin", u"RightMargin" };
- for (size_t i = 0; i < aMarginNames.size(); ++i)
- {
- beans::PropertyValue aMarginValue;
- aMarginValue.Name = aMarginNames[i];
- aMarginValue.Value <<= sal_Int32(10);
- rFrameProperties.push_back(aMarginValue);
- }
-}
-
}
TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo,
@@ -1440,8 +1408,10 @@ void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel, bool bTab
uno::Reference<text::XTextRange> xStart;
uno::Reference<text::XTextRange> xEnd;
- if ( bConvertToFloating )
- lcl_fillEmptyFrameProperties(aFrameProperties);
+ // fill empty frame properties to create an invisible frame around the table:
+ // hide frame borders and zero inner and outer frame margins
+ if (bConvertToFloating)
+ DomainMapper_Impl::fillEmptyFrameProperties(aFrameProperties, true);
// OOXML table style may contain paragraph properties, apply these on cell paragraphs
if ( m_aTableRanges[0].hasElements() && m_aTableRanges[0][0].hasElements() )
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index e5823f6b43e5..75812194a12d 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -2600,6 +2600,64 @@ void DomainMapper_Impl::appendGlossaryEntry()
appendTextSectionAfter(m_xGlossaryEntryStart);
}
+void DomainMapper_Impl::fillEmptyFrameProperties(std::vector<beans::PropertyValue>& rFrameProperties, bool bSetAnchorToChar)
+{
+ if (bSetAnchorToChar)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_ANCHOR_TYPE), text::TextContentAnchorType_AS_CHARACTER));
+
+ uno::Any aEmptyBorder = uno::makeAny(table::BorderLine2());
+ static const std::vector<PropertyIds> aBorderIds
+ = { PROP_BOTTOM_BORDER, PROP_LEFT_BORDER, PROP_RIGHT_BORDER, PROP_TOP_BORDER };
+ for (size_t i = 0; i < aBorderIds.size(); ++i)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(aBorderIds[i]), aEmptyBorder));
+
+ static const std::vector<PropertyIds> aMarginIds
+ = { PROP_BOTTOM_MARGIN, PROP_BOTTOM_BORDER_DISTANCE,
+ PROP_LEFT_MARGIN, PROP_LEFT_BORDER_DISTANCE,
+ PROP_RIGHT_MARGIN, PROP_RIGHT_BORDER_DISTANCE,
+ PROP_TOP_MARGIN, PROP_TOP_BORDER_DISTANCE };
+ for (size_t i = 0; i < aMarginIds.size(); ++i)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(aMarginIds[i]), static_cast<sal_Int32>(0)));
+}
+
+void DomainMapper_Impl::ConvertHeaderFooterToTextFrame(bool bDynamicHeightTop, bool bDynamicHeightBottom)
+{
+ while (!m_aHeaderFooterTextAppendStack.empty())
+ {
+ auto aFooterHeader = m_aHeaderFooterTextAppendStack.top();
+ if ((aFooterHeader.second && !bDynamicHeightTop) || (!aFooterHeader.second && !bDynamicHeightBottom))
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = aFooterHeader.first.xTextAppend;
+ uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursor();
+ uno::Reference< text::XTextRange > xRangeStart, xRangeEnd;
+
+ xRangeStart = xCursor->getStart();
+ xCursor->gotoEnd(false);
+ xRangeEnd = xCursor->getStart();
+
+ std::vector<beans::PropertyValue> aFrameProperties;
+
+ aFrameProperties.push_back(comphelper::makePropertyValue("TextWrap", css::text::WrapTextMode_THROUGH));
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT), text::HoriOrientation::LEFT));
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_OPAQUE), false));
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE), text::SizeType::MIN));
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SIZE_TYPE), text::SizeType::MIN));
+
+ fillEmptyFrameProperties(aFrameProperties, false);
+
+ // If it is a footer, then orient the frame to the bottom
+ if (!aFooterHeader.second)
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT), text::VertOrientation::BOTTOM));
+
+ uno::Reference<text::XTextAppendAndConvert> xBodyText(
+ xRangeStart->getText(), uno::UNO_QUERY);
+ xBodyText->convertToTextFrame(xRangeStart, xRangeEnd,
+ comphelper::containerToSequence(aFrameProperties));
+ }
+ m_aHeaderFooterTextAppendStack.pop();
+ }
+}
+
void DomainMapper_Impl::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType)
{
m_bSaveParaHadField = m_bParaHadField;
@@ -2662,6 +2720,11 @@ void DomainMapper_Impl::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::P
m_bIsNewDoc
? uno::Reference<text::XTextCursor>()
: xText->createTextCursorByRange(xText->getStart())));
+ m_aHeaderFooterTextAppendStack.push(std::make_pair(TextAppendContext(uno::Reference< text::XTextAppend >(xText, uno::UNO_QUERY_THROW),
+ m_bIsNewDoc
+ ? uno::Reference<text::XTextCursor>()
+ : xText->createTextCursorByRange(xText->getStart())),
+ bHeader));
m_bDiscardHeaderFooter = false; // set only on success!
}
// If we have *hidden* header footer
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 5212653dcd47..845e902a9ee3 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -467,6 +467,7 @@ private:
std::stack<TextAppendContext> m_aTextAppendStack;
std::stack<AnchoredContext> m_aAnchoredStack;
std::stack<HeaderFooterContext> m_aHeaderFooterStack;
+ std::stack<std::pair<TextAppendContext, bool>> m_aHeaderFooterTextAppendStack;
std::deque<FieldContextPtr> m_aFieldStack;
bool m_bForceGenericFields;
bool m_bSetUserFieldContent;
@@ -820,6 +821,8 @@ public:
void PopPageHeaderFooter();
bool IsInHeaderFooter() const { return m_eInHeaderFooterImport != HeaderFooterImportState::none; }
+ void ConvertHeaderFooterToTextFrame(bool, bool);
+ static void fillEmptyFrameProperties(std::vector<css::beans::PropertyValue>& rFrameProperties, bool bSetAnchorToChar);
bool IsInTOC() const { return m_bStartTOC; }
diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx
index 9b4c819e35cb..cacadef477d4 100644
--- a/writerfilter/source/dmapper/PropertyMap.cxx
+++ b/writerfilter/source/dmapper/PropertyMap.cxx
@@ -425,6 +425,8 @@ SectionPropertyMap::SectionPropertyMap( bool bIsFirstSection )
, m_nLnc(NS_ooxml::LN_Value_ST_LineNumberRestart_newPage)
, m_ndxaLnn( 0 )
, m_nLnnMin( 0 )
+ , m_bDynamicHeightTop( true )
+ , m_bDynamicHeightBottom( true )
, m_bDefaultHeaderLinkToPrevious( true )
, m_bEvenPageHeaderLinkToPrevious( true )
, m_bFirstPageHeaderLinkToPrevious( true )
@@ -982,28 +984,25 @@ void SectionPropertyMap::PrepareHeaderFooterProperties( bool bFirstPage )
bool bCopyFirstToFollow = bFirstPage && m_bTitlePage && m_aFollowPageStyle.is();
sal_Int32 nTopMargin = m_nTopMargin;
- sal_Int32 nHeaderTop = m_nHeaderTop;
+ sal_Int32 nHeaderHeight = m_nHeaderTop;
if ( HasHeader( bFirstPage ) )
{
- nTopMargin = nHeaderTop;
- if ( m_nTopMargin > 0 && m_nTopMargin > nHeaderTop )
- nHeaderTop = m_nTopMargin - nHeaderTop;
- else
- nHeaderTop = 0;
+ nTopMargin = m_nHeaderTop;
+ nHeaderHeight = m_nTopMargin - m_nHeaderTop;
// minimum header height 1mm
- if ( nHeaderTop < MIN_HEAD_FOOT_HEIGHT )
- nHeaderTop = MIN_HEAD_FOOT_HEIGHT;
+ if ( nHeaderHeight < MIN_HEAD_FOOT_HEIGHT )
+ nHeaderHeight = MIN_HEAD_FOOT_HEIGHT;
}
+ Insert(PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny(m_bDynamicHeightTop));
+ Insert(PROP_HEADER_DYNAMIC_SPACING, uno::makeAny(m_bDynamicHeightTop));
+ Insert(PROP_HEADER_BODY_DISTANCE, uno::makeAny(nHeaderHeight - MIN_HEAD_FOOT_HEIGHT));
+ Insert(PROP_HEADER_HEIGHT, uno::makeAny(nHeaderHeight));
+ // looks like PROP_HEADER_HEIGHT = height of the header + space between the header, and the body
- if ( m_nTopMargin >= 0 ) //fixed height header -> see WW8Par6.hxx
+ if ( m_bDynamicHeightTop ) //fixed height header -> see WW8Par6.hxx
{
- Insert( PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny( true ) );
- Insert( PROP_HEADER_DYNAMIC_SPACING, uno::makeAny( true ) );
- Insert( PROP_HEADER_BODY_DISTANCE, uno::makeAny( nHeaderTop - MIN_HEAD_FOOT_HEIGHT ) );// ULSpace.Top()
- Insert( PROP_HEADER_HEIGHT, uno::makeAny( nHeaderTop ) );
-
if (bCopyFirstToFollow && HasHeader(/*bFirstPage=*/true))
{
m_aFollowPageStyle->setPropertyValue("HeaderDynamicSpacing",
@@ -1012,36 +1011,25 @@ void SectionPropertyMap::PrepareHeaderFooterProperties( bool bFirstPage )
getProperty(PROP_HEADER_HEIGHT)->second);
}
}
- else
- {
- //todo: old filter fakes a frame into the header/footer to support overlapping
- //current setting is completely wrong!
- Insert( PROP_HEADER_HEIGHT, uno::makeAny( nHeaderTop ) );
- Insert( PROP_HEADER_BODY_DISTANCE, uno::makeAny( m_nTopMargin - nHeaderTop ) );
- Insert( PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny( false ) );
- Insert( PROP_HEADER_DYNAMIC_SPACING, uno::makeAny( false ) );
- }
sal_Int32 nBottomMargin = m_nBottomMargin;
- sal_Int32 nHeaderBottom = m_nHeaderBottom;
+ sal_Int32 nFooterHeight = m_nHeaderBottom;
if ( HasFooter( bFirstPage ) )
{
- nBottomMargin = nHeaderBottom;
- if ( m_nBottomMargin > 0 && m_nBottomMargin > nHeaderBottom )
- nHeaderBottom = m_nBottomMargin - nHeaderBottom;
- else
- nHeaderBottom = 0;
- if ( nHeaderBottom < MIN_HEAD_FOOT_HEIGHT )
- nHeaderBottom = MIN_HEAD_FOOT_HEIGHT;
+ nBottomMargin = m_nHeaderBottom;
+ nFooterHeight = m_nBottomMargin - m_nHeaderBottom;
+
+ // minimum footer height 1mm
+ if ( nFooterHeight < MIN_HEAD_FOOT_HEIGHT )
+ nFooterHeight = MIN_HEAD_FOOT_HEIGHT;
}
- if ( m_nBottomMargin >= 0 ) //fixed height footer -> see WW8Par6.hxx
+ Insert(PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny(m_bDynamicHeightBottom));
+ Insert(PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny(m_bDynamicHeightBottom));
+ Insert(PROP_FOOTER_BODY_DISTANCE, uno::makeAny(nFooterHeight - MIN_HEAD_FOOT_HEIGHT));
+ Insert(PROP_FOOTER_HEIGHT, uno::makeAny(nFooterHeight));
+ if (m_bDynamicHeightBottom) //fixed height footer -> see WW8Par6.hxx
{
- Insert( PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny( true ) );
- Insert( PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny( true ) );
- Insert( PROP_FOOTER_BODY_DISTANCE, uno::makeAny( nHeaderBottom - MIN_HEAD_FOOT_HEIGHT ) );
- Insert( PROP_FOOTER_HEIGHT, uno::makeAny( nHeaderBottom ) );
-
if (bCopyFirstToFollow && HasFooter(/*bFirstPage=*/true))
{
m_aFollowPageStyle->setPropertyValue("FooterDynamicSpacing",
@@ -1050,15 +1038,6 @@ void SectionPropertyMap::PrepareHeaderFooterProperties( bool bFirstPage )
getProperty(PROP_FOOTER_HEIGHT)->second);
}
}
- else
- {
- //todo: old filter fakes a frame into the header/footer to support overlapping
- //current setting is completely wrong!
- Insert( PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny( false ) );
- Insert( PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny( false ) );
- Insert( PROP_FOOTER_HEIGHT, uno::makeAny( m_nBottomMargin - nHeaderBottom ) );
- Insert( PROP_FOOTER_BODY_DISTANCE, uno::makeAny( nHeaderBottom ) );
- }
//now set the top/bottom margin for the follow page style
Insert( PROP_TOP_MARGIN, uno::makeAny( std::max<sal_Int32>(nTopMargin, 0) ) );
@@ -1134,6 +1113,13 @@ void SectionPropertyMap::HandleMarginsHeaderFooter( bool bFirstPage, DomainMappe
*/
CopyLastHeaderFooter( bFirstPage, rDM_Impl );
PrepareHeaderFooterProperties( bFirstPage );
+
+ // tdf#119952: If top/bottom margin was negative during docx import,
+ // then the header/footer and the body could be on top of each other
+ // writer is unable to display both of them in the same position, but can be simulated
+ // by moving the header/footer text into a flyframe anchored to the header/footer,
+ // leaving an empty dummy header/footer.
+ rDM_Impl.ConvertHeaderFooterToTextFrame(m_bDynamicHeightTop, m_bDynamicHeightBottom);
}
bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_Impl, FloatingTableInfo& rInfo )
diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx
index d4f981c5db91..917849957ce0 100644
--- a/writerfilter/source/dmapper/PropertyMap.hxx
+++ b/writerfilter/source/dmapper/PropertyMap.hxx
@@ -270,6 +270,9 @@ private:
sal_Int32 m_ndxaLnn;
sal_Int32 m_nLnnMin;
+ bool m_bDynamicHeightTop;
+ bool m_bDynamicHeightBottom;
+
std::vector<css::uno::Reference<css::drawing::XShape>> m_xRelativeWidthShapes;
// The "Link To Previous" flag indicates whether the header/footer
@@ -378,8 +381,8 @@ public:
sal_Int32 GetLeftMargin() const { return m_nLeftMargin; }
void SetRightMargin( sal_Int32 nSet ) { m_nRightMargin = nSet; }
sal_Int32 GetRightMargin() const { return m_nRightMargin; }
- void SetTopMargin( sal_Int32 nSet ) { m_nTopMargin = nSet; }
- void SetBottomMargin( sal_Int32 nSet ) { m_nBottomMargin = nSet; }
+ void SetTopMargin(sal_Int32 nSet) { m_bDynamicHeightTop = nSet >= 0; m_nTopMargin = std::abs(nSet); }
+ void SetBottomMargin( sal_Int32 nSet ) { m_bDynamicHeightBottom = nSet >= 0; m_nBottomMargin = std::abs(nSet); }
void SetHeaderTop( sal_Int32 nSet ) { m_nHeaderTop = nSet; }
void SetHeaderBottom( sal_Int32 nSet ) { m_nHeaderBottom = nSet; }
void SetGutterMargin( sal_Int32 nGutterMargin ) { m_nGutterMargin = nGutterMargin; }