diff options
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf115719.docx | bin | 0 -> 11905 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport11.cxx | 7 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapperTableHandler.cxx | 30 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 17 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.hxx | 16 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.cxx | 68 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.hxx | 4 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SettingsTable.cxx | 27 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SettingsTable.hxx | 2 |
9 files changed, 142 insertions, 29 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/tdf115719.docx b/sw/qa/extras/ooxmlexport/data/tdf115719.docx Binary files differnew file mode 100644 index 000000000000..9519a2a14524 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf115719.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx index 58e654159494..98e207c81d81 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx @@ -99,6 +99,13 @@ DECLARE_OOXMLEXPORT_TEST(testTdf67207_MERGEFIELD, "mailmerge.docx") CPPUNIT_ASSERT_EQUAL(OUString("com.sun.star.text.fieldmaster.DataBase.Name"), sValue); } +DECLARE_OOXMLEXPORT_TEST(testTdf115719, "tdf115719.docx") +{ + // This was a single page, instead of pushing the textboxes to the second + // page. + CPPUNIT_ASSERT_EQUAL(2, getPages()); +} + DECLARE_OOXMLEXPORT_TEST(testTdf113183, "tdf113183.docx") { // This was 2096, the horizontal positioning of the star shape affected the diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx index 2f254be9c67c..e6f993e19387 100644 --- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx +++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx @@ -312,34 +312,6 @@ void lcl_DecrementHoriOrientPosition(std::vector<beans::PropertyValue>& rFramePr } } -sal_Int32 lcl_getWordCompatibilityMode( const css::uno::Sequence< css::beans::PropertyValue >& rCompatSettings ) -{ - for ( int i = 0; i < rCompatSettings.getLength(); ++i ) - { - const css::beans::PropertyValue& rProp = rCompatSettings[i]; - if ( rProp.Name == "compatSetting" ) - { - css::uno::Sequence< css::beans::PropertyValue > aCurrentCompatSettings; - rProp.Value >>= aCurrentCompatSettings; - - OUString sName; - OUString sUri; - OUString sVal; - - aCurrentCompatSettings[0].Value >>= sName; - aCurrentCompatSettings[1].Value >>= sUri; - aCurrentCompatSettings[2].Value >>= sVal; - - if ( sName == "compatibilityMode" && sUri == "http://schemas.microsoft.com/office/word" ) - { - return sVal.toInt32(); - } - } - } - - return -1; // Word compatibility mode not found -} - TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo, std::vector<beans::PropertyValue>& rFrameProperties) { // will receive the table style if any @@ -574,7 +546,7 @@ TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo // tdf#106742: since MS Word 2013 (compatibilityMode >= 15), top-level tables are handled the same as nested tables; // this is also the default behavior in LO when DOCX doesn't define "compatibilityMode" option - sal_Int32 nMode = lcl_getWordCompatibilityMode( m_rDMapper_Impl.GetSettingsTable()->GetCompatSettings() ); + sal_Int32 nMode = m_rDMapper_Impl.GetSettingsTable()->GetWordCompatibilityMode(); if ( nMode > 0 && nMode <= 14 && rInfo.nNestLevel == 1 ) { diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 115bdb002688..ff412635b6fa 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -1247,6 +1247,17 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap ) xTextRange = xTextAppend->finishParagraph( comphelper::containerToSequence(aProperties) ); m_xPreviousParagraph.set(xTextRange, uno::UNO_QUERY); + + if (!rAppendContext.m_aAnchoredObjects.empty()) + { + // Remember what objects are anchored to this paragraph. + AnchoredObjectInfo aInfo; + aInfo.m_xParagraph = xTextRange; + aInfo.m_aAnchoredObjects = rAppendContext.m_aAnchoredObjects; + m_aAnchoredObjectAnchors.push_back(aInfo); + rAppendContext.m_aAnchoredObjects.clear(); + } + // We're no longer right after a table conversion. m_bConvertedTable = false; @@ -5130,8 +5141,14 @@ void DomainMapper_Impl::ImportGraphic(const writerfilter::Reference< Properties //insert it into the document at the current cursor position OSL_ENSURE( xTextContent.is(), "DomainMapper_Impl::ImportGraphic"); if( xTextContent.is()) + { appendTextContent( xTextContent, uno::Sequence< beans::PropertyValue >() ); + if (eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR && !m_aTextAppendStack.empty()) + // Remember this object is anchored to the current paragraph. + m_aTextAppendStack.top().m_aAnchoredObjects.push_back(xTextContent); + } + // Clear the reference, so in case the embedded object is inside a // TextFrame, we won't try to resize it (to match the size of the // TextFrame) here. diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index cf51e7fac46c..807f80164342 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -215,6 +215,12 @@ struct TextAppendContext css::uno::Reference<css::text::XParagraphCursor> xCursor; ParagraphPropertiesPtr pLastParagraphProperties; + /** + * Objects anchored to the current paragraph, may affect the paragraph + * spacing. + */ + std::vector<css::uno::Reference<css::text::XTextContent>> m_aAnchoredObjects; + TextAppendContext(const css::uno::Reference<css::text::XTextAppend>& xAppend, const css::uno::Reference<css::text::XTextCursor>& xCur) : xTextAppend(xAppend) { @@ -374,6 +380,13 @@ struct FloatingTableInfo css::uno::Any getPropertyValue(const OUString &propertyName); }; +/// Stores info about objects anchored to a given paragraph. +struct AnchoredObjectInfo +{ + css::uno::Reference<css::text::XTextRange> m_xParagraph; + std::vector<css::uno::Reference<css::text::XTextContent>> m_aAnchoredObjects; +}; + struct SymbolData { sal_Unicode cSymbol; @@ -915,6 +928,9 @@ public: /// Pending floating tables: they may be converted to text frames at the section end. std::vector<FloatingTableInfo> m_aPendingFloatingTables; + /// Paragraphs with anchored objects in the current section. + std::vector<AnchoredObjectInfo> m_aAnchoredObjectAnchors; + /// Append a property to a sub-grabbag if necessary (e.g. 'lineRule', 'auto') void appendGrabBag(std::vector<css::beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, const OUString& aValue); void appendGrabBag(std::vector<css::beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, std::vector<css::beans::PropertyValue>& rValue); diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx index b1ee1fd971a3..84625c073d57 100644 --- a/writerfilter/source/dmapper/PropertyMap.cxx +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -1126,6 +1126,72 @@ void SectionPropertyMap::InheritOrFinalizePageStyles( DomainMapper_Impl& rDM_Imp } } +void SectionPropertyMap::HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl& rDM_Impl) +{ + // Ignore Word 2010 and older. + if (rDM_Impl.GetSettingsTable()->GetWordCompatibilityMode() < 15) + return; + + sal_Int32 nPageWidth = GetPageWidth(); + sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin(); + + std::vector<AnchoredObjectInfo>& rAnchoredObjectAnchors = rDM_Impl.m_aAnchoredObjectAnchors; + for (auto& rAnchor : rAnchoredObjectAnchors) + { + // Analyze the anchored objects of this paragraph, now that we know the + // page width. + sal_Int32 nShapesWidth = 0; + for (const auto& rAnchored : rAnchor.m_aAnchoredObjects) + { + uno::Reference<drawing::XShape> xShape(rAnchored, uno::UNO_QUERY); + if (!xShape.is()) + continue; + + uno::Reference<beans::XPropertySet> xPropertySet(rAnchored, uno::UNO_QUERY); + if (!xPropertySet.is()) + continue; + + // Ignore objects with no wrapping. + text::WrapTextMode eWrap = text::WrapTextMode_THROUGH; + xPropertySet->getPropertyValue("Surround") >>= eWrap; + if (eWrap == text::WrapTextMode_THROUGH) + continue; + + sal_Int32 nLeftMargin = 0; + xPropertySet->getPropertyValue("LeftMargin") >>= nLeftMargin; + sal_Int32 nRightMargin = 0; + xPropertySet->getPropertyValue("RightMargin") >>= nRightMargin; + nShapesWidth += xShape->getSize().Width + nLeftMargin + nRightMargin; + } + + // Ignore cases when we have enough horizontal space for the shapes. + if (nTextAreaWidth > nShapesWidth) + continue; + + sal_Int32 nHeight = 0; + for (const auto& rAnchored : rAnchor.m_aAnchoredObjects) + { + uno::Reference<drawing::XShape> xShape(rAnchored, uno::UNO_QUERY); + if (!xShape.is()) + continue; + + nHeight += xShape->getSize().Height; + } + + uno::Reference<beans::XPropertySet> xParagraph(rAnchor.m_xParagraph, uno::UNO_QUERY); + if (xParagraph.is()) + { + sal_Int32 nTopMargin = 0; + xParagraph->getPropertyValue("ParaTopMargin") >>= nTopMargin; + // Increase top spacing of the paragraph to match Word layout + // behavior. + nTopMargin = std::max(nTopMargin, nHeight); + xParagraph->setPropertyValue("ParaTopMargin", uno::makeAny(nTopMargin)); + } + } + rAnchoredObjectAnchors.clear(); +} + void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) { // The default section type is nextPage. @@ -1143,6 +1209,8 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) } rPendingFloatingTables.clear(); + HandleIncreasedAnchoredObjectSpacing(rDM_Impl); + if ( m_nLnnMod ) { bool bFirst = rDM_Impl.IsLineNumberingSet(); diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx index d7f416f79607..2412c8e0126e 100644 --- a/writerfilter/source/dmapper/PropertyMap.hxx +++ b/writerfilter/source/dmapper/PropertyMap.hxx @@ -59,6 +59,7 @@ namespace dmapper { class DomainMapper_Impl; struct FloatingTableInfo; +struct AnchoredObjectInfo; enum BorderPosition { @@ -278,6 +279,9 @@ private: // Determines if conversion of a given floating table is wanted or not. bool FloatingTableConversion( DomainMapper_Impl& rDM_Impl, FloatingTableInfo& rInfo ); + /// Increases paragraph spacing according to Word 2013+ needs if necessary. + void HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl& rDM_Impl); + public: enum PageType { diff --git a/writerfilter/source/dmapper/SettingsTable.cxx b/writerfilter/source/dmapper/SettingsTable.cxx index b747eb37abdb..d782b2c11603 100644 --- a/writerfilter/source/dmapper/SettingsTable.cxx +++ b/writerfilter/source/dmapper/SettingsTable.cxx @@ -617,6 +617,33 @@ void SettingsTable::ApplyProperties(uno::Reference<text::XTextDocument> const& x } } +sal_Int32 SettingsTable::GetWordCompatibilityMode() const +{ + for (const auto& rProp : m_pImpl->m_aCompatSettings) + { + if (rProp.Name == "compatSetting") + { + css::uno::Sequence<css::beans::PropertyValue> aCurrentCompatSettings; + rProp.Value >>= aCurrentCompatSettings; + + OUString sName; + OUString sUri; + OUString sVal; + + aCurrentCompatSettings[0].Value >>= sName; + aCurrentCompatSettings[1].Value >>= sUri; + aCurrentCompatSettings[2].Value >>= sVal; + + if (sName == "compatibilityMode" && sUri == "http://schemas.microsoft.com/office/word") + { + return sVal.toInt32(); + } + } + } + + return -1; // Word compatibility mode not found +} + }//namespace dmapper } //namespace writerfilter diff --git a/writerfilter/source/dmapper/SettingsTable.hxx b/writerfilter/source/dmapper/SettingsTable.hxx index 2a80bd186fc1..dafba061947b 100644 --- a/writerfilter/source/dmapper/SettingsTable.hxx +++ b/writerfilter/source/dmapper/SettingsTable.hxx @@ -83,6 +83,8 @@ class SettingsTable : public LoggedProperties, public LoggedTable void ApplyProperties(css::uno::Reference<css::text::XTextDocument> const& xDoc); + sal_Int32 GetWordCompatibilityMode() const; + private: // Properties virtual void lcl_attribute(Id Name, Value & val) override; |