diff options
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf119952_negativeMargins.docx | bin | 0 -> 23533 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport11.cxx | 83 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapperTableHandler.cxx | 38 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 63 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.hxx | 3 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.cxx | 78 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.hxx | 7 |
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 Binary files differnew file mode 100644 index 000000000000..9b5a98d3f1aa --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf119952_negativeMargins.docx 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; } |