oox/source/vml/vmlshapecontext.cxx | 1 sw/qa/extras/ooxmlexport/data/tdf126533_noPageBitmap.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport21.cxx | 21 +++++ writerfilter/source/dmapper/DomainMapper.cxx | 58 ++++++++++++++ writerfilter/source/dmapper/DomainMapper_Impl.hxx | 1 writerfilter/source/dmapper/PropertyMap.cxx | 33 +++++++ writerfilter/source/ooxml/model.xml | 3 7 files changed, 115 insertions(+), 2 deletions(-)
New commits: commit ec36ecb408bd77f1fa2d823454968f50d32f745c Author: Justin Luth <justin.l...@collabora.com> AuthorDate: Sat Feb 3 10:08:56 2024 -0500 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Feb 26 08:42:19 2024 +0100 tdf#126533 docx import: page background vml fill This patch imports bitmaps/tiled textures (primarily), but also somewhat for gradients (because of a gradient2 -> gradient mismatch somewhere) and somewhat for patterns (because patterns are not well imported in general). Note that the imported fill likely will NOT match MSO, because their background CHANGES BASED ON THE ZOOM LEVEL. For example, my primary testing file (A6 landscape) has a logo which is only 25% visible in Word 2003 at 100%, but shows 90% of the logo at 200%, and many tiles of logos when exported as PDF. The same is true for gradients etc. Changing background on zoom is an absolutely bizarre implementation, and naturally LO could only accidentally look identical (and should never try to do so). make CppunitTest_sw_ooxmlexport21 \ CPPUNIT_TEST_NAME=testTdf126533_noPageBitmap make CppunitTest_sw_ooxmlexport21 \ CPPUNIT_TEST_NAME=testTdf126533_pageGradient This is slightly ugly, but I don't know how to make a COPY of the XPropertySet UNO junk. All I have is references, and dispose deletes everything, even the references. I took some inspiration from RTF which just disposes the shape after grabbing the background color. Thus, just change the page style known to exist and be used, and then simply remove the fill if it isn't needed in the end. Any new page styles can just copy the default page style fill. Change-Id: Id3ea002c685642ff4c289982d0108247a6e9bb8d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162958 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163861 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Justin Luth <jl...@mail.com> diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx index e3242368a334..20ce2fa37434 100644 --- a/oox/source/vml/vmlshapecontext.cxx +++ b/oox/source/vml/vmlshapecontext.cxx @@ -251,6 +251,7 @@ ContextHandlerRef ShapeContextBase::createShapeContext( ContextHandler2Helper co return new ShapeContext( rParent, rShapes.createShape< BezierShape >(), rAttribs ); else return new ShapeContext( rParent, rShapes.createShape< ComplexShape >(), rAttribs ); + case VML_TOKEN(background): case VML_TOKEN( rect ): return new RectangleShapeContext( rParent, rAttribs, rShapes.createShape< RectangleShape >() ); case VML_TOKEN( roundrect ): diff --git a/sw/qa/core/data/ooxml/pass/fill.docx b/sw/qa/extras/ooxmlexport/data/fill.docx similarity index 100% rename from sw/qa/core/data/ooxml/pass/fill.docx rename to sw/qa/extras/ooxmlexport/data/fill.docx diff --git a/sw/qa/extras/ooxmlexport/data/tdf126533_noPageBitmap.docx b/sw/qa/extras/ooxmlexport/data/tdf126533_noPageBitmap.docx new file mode 100644 index 000000000000..87dfff296be5 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf126533_noPageBitmap.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx index cdcdfe778577..ca0cc5438ee6 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx @@ -10,6 +10,7 @@ #include <swmodeltestbase.hxx> #include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/text/XDocumentIndex.hpp> #include <com/sun/star/text/XTextTable.hpp> #include <com/sun/star/style/LineSpacing.hpp> @@ -62,6 +63,26 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf159207_footerFramePrBorder) // TODO: there SHOULD BE a top border, and even if loaded, it would be lost on re-import... } +DECLARE_OOXMLEXPORT_TEST(testTdf126533_noPageBitmap, "tdf126533_noPageBitmap.docx") +{ + // given a document with a v:background bitmap, but no w:background fillcolor + uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName("Standard"), + uno::UNO_QUERY); + // the image (or any fill for that matter) should be ignored. + CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, + getProperty<drawing::FillStyle>(xPageStyle, "FillStyle")); +} + +CPPUNIT_TEST_FIXTURE(Test, testTdf126533_pageGradient) +{ + // given a document with a gradient page background + loadFromFile(u"fill.docx"); + uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName("Standard"), + uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT, + getProperty<drawing::FillStyle>(xPageStyle, "FillStyle")); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index bbeafa942de4..50f47439af27 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -32,6 +32,8 @@ #include <ooxml/resourceids.hxx> #include <oox/token/tokens.hxx> #include <oox/drawingml/drawingmltypes.hxx> + +#include <com/sun/star/awt/Gradient2.hpp> #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> #include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp> #include <com/sun/star/drawing/FillStyle.hpp> @@ -1475,7 +1477,63 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext ) switch (rSprm.getId()) { case NS_ooxml::LN_background_background: + { + // if a VML background has been defined, it was imported into a shape to hold the properties + uno::Reference<drawing::XShape> xFill(m_pImpl->PopPendingShape()); + if (xFill.is()) + { + assert(!m_pImpl->GetTopContext()); + assert(m_pImpl->GetIsFirstParagraphInShape()); + assert(mbWasShapeInPara); + assert(m_pImpl->GetIsFirstParagraphInSection()); + assert(m_pImpl->IsOutsideAParagraph()); + if (m_pImpl->GetSettingsTable()->GetDisplayBackgroundShape()) + { + // apply the XATTR_FILL attributes to the default page style + const uno::Reference<beans::XPropertySet> xFillPropertySet(xFill, uno::UNO_QUERY); + const uno::Reference<beans::XPropertySetInfo> xFillInfo + = xFillPropertySet->getPropertySetInfo(); + uno::Reference<beans::XPropertySet> xPS( + m_pImpl->GetPageStyles()->getByName("Standard"), uno::UNO_QUERY_THROW); + for (const beans::Property& rProp : xPS->getPropertySetInfo()->getProperties()) + { + if (rProp.Name == "FillComplexColor" || rProp.Name == "FillGradientName" + || rProp.Name == "FillGradientStepCount" + || rProp.Name == "FillTransparenceGradientName" + || rProp.Name == "FillBitmapURL" || rProp.Name == "FillColor2") + { + // silence exceptions for unsupported stuff when appling to page style + continue; + } + if (!rProp.Name.startsWith("Fill")) + continue; + + if (!xFillInfo->hasPropertyByName(rProp.Name)) + continue; + + try + { + const uno::Any aFillValue = xFillPropertySet->getPropertyValue(rProp.Name); + xPS->setPropertyValue(rProp.Name, aFillValue); + } + catch (uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("writerfilter", "Exception setting page background fill"); + } + } + + m_pImpl->m_bCopyStandardPageStyleFill = true; + } + + // The background was unhelpfully imported into the text body: remove it + uno::Reference<lang::XComponent> xComponent(xFill, uno::UNO_QUERY_THROW); + xComponent->dispose(); + + m_pImpl->SetIsFirstParagraphInShape(false); + mbWasShapeInPara = false; + } return; + } default: break; } diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index 7db3dbcddcae..0a0bb4cf4f8a 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -1141,6 +1141,7 @@ public: /// Document background color, applied to every page style. std::optional<sal_Int32> m_oBackgroundColor; + bool m_bCopyStandardPageStyleFill = false; /// Raw table cell depth. sal_Int32 m_nTableCellDepth; diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx index 9c3e031e40b0..15ba4bb582e1 100644 --- a/writerfilter/source/dmapper/PropertyMap.cxx +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -40,6 +40,7 @@ #include <com/sun/star/container/XEnumeration.hpp> #include <com/sun/star/container/XEnumerationAccess.hpp> #include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/style/BreakType.hpp> #include <com/sun/star/style/PageStyleLayout.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> @@ -1134,7 +1135,37 @@ void SectionPropertyMap::HandleMarginsHeaderFooter(DomainMapper_Impl& rDM_Impl) Insert( PROP_RIGHT_MARGIN, uno::Any( m_nRightMargin ) ); Insert(PROP_GUTTER_MARGIN, uno::Any(m_nGutterMargin)); - if ( rDM_Impl.m_oBackgroundColor ) + // w:background is applied to every page in the document + if (!rDM_Impl.m_oBackgroundColor.has_value() && !rDM_Impl.IsRTFImport()) + { + // DOCX has an interesting quirk, where if the fallback background color is not defined, + // then the fill is not applied either. + + // Disable the imported fill from the default style + if (rDM_Impl.m_bCopyStandardPageStyleFill && m_sPageStyleName == "Standard") + { + rDM_Impl.m_bCopyStandardPageStyleFill = false; + m_aPageStyle->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE)); + } + } + else if (rDM_Impl.m_bCopyStandardPageStyleFill) // complex fill: graphics/gradients/patterns + { + uno::Reference<beans::XPropertySet> xDefaultPageStyle( + rDM_Impl.GetPageStyles()->getByName("Standard"), uno::UNO_QUERY_THROW); + for (const beans::Property& rProp : m_aPageStyle->getPropertySetInfo()->getProperties()) + { + try + { + const uno::Any aFillValue = xDefaultPageStyle->getPropertyValue(rProp.Name); + m_aPageStyle->setPropertyValue(rProp.Name, aFillValue); + } + catch (uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("writerfilter", "Exception setting page background fill"); + } + } + } + else if (rDM_Impl.m_oBackgroundColor) // simple, solid color Insert( PROP_BACK_COLOR, uno::Any( *rDM_Impl.m_oBackgroundColor ) ); // Check for missing footnote separator only in case there is at least diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml index 2c174743f990..2f84e72c0615 100644 --- a/writerfilter/source/ooxml/model.xml +++ b/writerfilter/source/ooxml/model.xml @@ -17744,12 +17744,13 @@ <element name="sectPr" tokenid="ooxml:CT_PPr_sectPr"/> <element name="pPrChange" tokenid="ooxml:CT_PPr_pPrChange"/> </resource> - <resource name="CT_Background" resource="Properties"> + <resource name="CT_Background" resource="Shape"> <attribute name="color" tokenid="ooxml:CT_Background_color"/> <attribute name="themeColor" tokenid="ooxml:CT_Background_themeColor"/> <attribute name="themeTint" tokenid="ooxml:CT_Background_themeTint"/> <attribute name="themeShade" tokenid="ooxml:CT_Background_themeShade"/> <element name="v:background" tokenid="ooxml:CT_Background_v_background"/> + <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:background_background"/> </resource> <resource name="CT_Rel" resource="Properties"> <attribute name="r:id" tokenid="ooxml:CT_Rel_id"/>