basegfx/source/tools/gradienttools.cxx | 925 ++++++++++- canvas/source/vcl/canvashelper_texturefill.cxx | 4 chart2/qa/extras/chart2export3.cxx | 2 chart2/qa/extras/chart2geometry.cxx | 33 chart2/qa/extras/chart2import.cxx | 34 chart2/source/controller/main/ChartController_Tools.cxx | 7 cppcanvas/source/mtfrenderer/implrenderer.cxx | 14 cui/source/inc/cuitabarea.hxx | 12 cui/source/tabpages/tpgradnt.cxx | 46 cui/source/tabpages/tptrans.cxx | 47 desktop/source/lib/init.cxx | 21 drawinglayer/inc/texture/texture.hxx | 74 drawinglayer/qa/unit/vclpixelprocessor2d.cxx | 7 drawinglayer/source/attribute/fillgradientattribute.cxx | 112 - drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx | 309 +-- drawinglayer/source/primitive3d/textureprimitive3d.cxx | 9 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 72 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 161 + drawinglayer/source/processor3d/defaultprocessor3d.cxx | 70 drawinglayer/source/texture/texture.cxx | 629 +++++-- drawinglayer/source/tools/primitive2dxmldump.cxx | 33 drawinglayer/source/tools/wmfemfhelper.cxx | 56 filter/source/msfilter/escherex.cxx | 2 filter/source/msfilter/msdffimp.cxx | 8 filter/source/msfilter/svdfppt.cxx | 6 filter/source/svg/svgwriter.cxx | 20 include/basegfx/utils/gradienttools.hxx | 303 +++ include/drawinglayer/attribute/fillgradientattribute.hxx | 54 include/drawinglayer/primitive2d/fillgradientprimitive2d.hxx | 21 include/oox/export/drawingml.hxx | 19 include/oox/helper/modelobjecthelper.hxx | 3 include/svx/sidebar/AreaPropertyPanelBase.hxx | 6 include/svx/sidebar/AreaTransparencyGradientPopup.hxx | 4 include/svx/unomid.hxx | 1 include/svx/xgrad.hxx | 21 include/vcl/gradient.hxx | 7 include/vcl/vclenum.hxx | 12 include/xmloff/GradientStyle.hxx | 11 include/xmloff/xmltoken.hxx | 5 offapi/UnoApi_offapi.mk | 3 offapi/com/sun/star/awt/ColorStop.idl | 32 offapi/com/sun/star/awt/ColorStopSequence.idl | 17 offapi/com/sun/star/awt/Gradient2.idl | 26 oox/CppunitTest_oox_drawingml.mk | 1 oox/CppunitTest_oox_shape.mk | 1 oox/qa/unit/drawingml.cxx | 13 oox/source/drawingml/fillproperties.cxx | 347 ---- oox/source/drawingml/shapepropertymap.cxx | 16 oox/source/export/chartexport.cxx | 82 oox/source/export/drawingml.cxx | 349 ++-- oox/source/helper/modelobjecthelper.cxx | 12 oox/source/vml/vmlformatting.cxx | 3 reportdesign/source/ui/misc/UITools.cxx | 4 reportdesign/source/ui/report/EndMarker.cxx | 2 reportdesign/source/ui/report/ReportController.cxx | 3 reportdesign/source/ui/report/StartMarker.cxx | 2 sc/qa/unit/bugfix-test.cxx | 24 sc/source/ui/cctrl/tbzoomsliderctrl.cxx | 2 sc/source/ui/view/output.cxx | 2 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 72 sd/qa/unit/data/xml/n819614_0.xml | 102 - sd/qa/unit/export-tests-ooxml1.cxx | 38 sd/qa/unit/export-tests-ooxml2.cxx | 15 sd/qa/unit/export-tests-ooxml3.cxx | 30 sd/qa/unit/import-tests.cxx | 15 sd/qa/unit/misc-tests.cxx | 14 sd/qa/unit/uiimpress.cxx | 9 sd/source/core/drawdoc4.cxx | 49 sd/source/ui/annotations/annotationwindow.cxx | 2 sd/source/ui/sidebar/SlideBackground.cxx | 31 sd/source/ui/sidebar/SlideBackground.hxx | 6 sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx | 2 sd/source/ui/view/drviews9.cxx | 41 svx/source/customshapes/EnhancedCustomShape2d.cxx | 21 svx/source/sdr/attribute/sdrallfillattributeshelper.cxx | 11 svx/source/sdr/primitive2d/sdrattributecreator.cxx | 382 +++- svx/source/sidebar/area/AreaPropertyPanelBase.cxx | 49 svx/source/sidebar/area/AreaTransparencyGradientPopup.cxx | 29 svx/source/svdraw/gradtrns.cxx | 16 svx/source/svdraw/svdetc.cxx | 4 svx/source/svdraw/svdfmtf.cxx | 53 svx/source/svdraw/svdoashp.cxx | 10 svx/source/unodraw/XPropertyTable.cxx | 28 svx/source/unodraw/unobrushitemhelper.cxx | 8 svx/source/xml/xmlxtexp.cxx | 1 svx/source/xml/xmlxtimp.cxx | 125 + svx/source/xoutdev/xattr.cxx | 227 +- svx/source/xoutdev/xpool.cxx | 14 svx/source/xoutdev/xtabgrdt.cxx | 79 sw/CppunitTest_sw_odfexport.mk | 1 sw/ooxmlexport_setup.mk | 3 sw/qa/extras/odfexport/odfexport.cxx | 30 sw/qa/extras/ooxmlexport/ooxmlexport2.cxx | 38 sw/qa/extras/rtfexport/rtfexport.cxx | 42 sw/rtfexport_setup.mk | 1 sw/source/core/text/inftxt.cxx | 2 sw/source/core/unocore/unoframe.cxx | 6 sw/source/filter/ww8/docxattributeoutput.cxx | 4 sw/source/filter/ww8/rtfattributeoutput.cxx | 50 sw/source/uibase/docvw/AnnotationWin2.cxx | 2 sw/source/uibase/docvw/HeaderFooterWin.cxx | 5 sw/source/uibase/docvw/ShadowOverlayObject.cxx | 23 sw/source/uibase/docvw/SidebarTxtControl.cxx | 4 sw/source/uibase/sidebar/PageStylesPanel.cxx | 11 toolkit/source/awt/vclxgraphics.cxx | 2 vcl/backendtest/VisualBackendTest.cxx | 2 vcl/backendtest/outputdevice/gradient.cxx | 24 vcl/headless/SvpGraphicsBackend.cxx | 6 vcl/qa/cppunit/TypeSerializerTest.cxx | 5 vcl/qa/cppunit/gradient.cxx | 6 vcl/qa/cppunit/outdev.cxx | 10 vcl/qa/cppunit/svm/svmtest.cxx | 10 vcl/skia/gdiimpl.cxx | 10 vcl/source/filter/svm/SvmConverter.cxx | 2 vcl/source/gdi/TypeSerializer.cxx | 2 vcl/source/gdi/gradient.cxx | 28 vcl/source/gdi/mtfxmldump.cxx | 18 vcl/source/gdi/pdfwriter_impl.cxx | 26 vcl/source/gdi/pdfwriter_impl2.cxx | 4 vcl/source/gdi/wall.cxx | 2 vcl/source/outdev/gradient.cxx | 10 vcl/source/window/toolbox.cxx | 2 vcl/workben/svptest.cxx | 2 vcl/workben/vcldemo.cxx | 14 xmloff/qa/unit/data/MCGR_OldToNew.odg |binary xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg |binary xmloff/qa/unit/data/MCGR_threeStops.fodt | 317 +++ xmloff/qa/unit/style.cxx | 206 ++ xmloff/source/core/xmltoken.cxx | 5 xmloff/source/style/FillStyleContext.cxx | 105 + xmloff/source/style/FillStyleContext.hxx | 26 xmloff/source/style/GradientStyle.cxx | 118 + xmloff/source/style/TransGradientStyle.cxx | 48 xmloff/source/token/tokens.txt | 4 134 files changed, 4969 insertions(+), 1871 deletions(-)
New commits: commit fa0e3d5617c8398cb1afb0af7f0a9d53391e267e Author: Armin Le Grand (allotropia) <[email protected]> AuthorDate: Tue May 9 12:29:30 2023 +0200 Commit: Andras Timar <[email protected]> CommitDate: Mon May 15 21:38:55 2023 +0200 MCGR: Correct interpolate TextureMap due to possible zero value Change-Id: I5b2fe354077bea659f522e5b5c839be1f4cae1c4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151568 Tested-by: Jenkins Reviewed-by: Armin Le Grand <[email protected]> diff --git a/drawinglayer/source/texture/texture.cxx b/drawinglayer/source/texture/texture.cxx index 2b42b5353ac8..ec918ed522ef 100644 --- a/drawinglayer/source/texture/texture.cxx +++ b/drawinglayer/source/texture/texture.cxx @@ -116,7 +116,7 @@ namespace drawinglayer::texture return false; // not needed when the last two ColorStops have different offset, then - // a visible range will be pocessed already + // a visible range will be processed already if (!basegfx::fTools::equal(mnColorStops.back().getStopOffset(), penultimate->getStopOffset())) return false; @@ -243,7 +243,7 @@ namespace drawinglayer::texture // set and add at target aCallback( maGradientInfo.getTextureTransform() * aNew, - interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); + 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); } } @@ -367,7 +367,7 @@ namespace drawinglayer::texture // set and add at target aCallback( maGradientInfo.getTextureTransform() * aNew, - interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); + 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); } } @@ -462,7 +462,7 @@ namespace drawinglayer::texture // set and add at target aCallback( maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix(fSize, fSize), - interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); + 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); } } @@ -563,7 +563,7 @@ namespace drawinglayer::texture * basegfx::utils::createScaleB2DHomMatrix( 1.0 - (bMTO ? fSize / fAR : fSize), 1.0 - (bMTO ? fSize : fSize * fAR)), - interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); + 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); } } @@ -657,7 +657,7 @@ namespace drawinglayer::texture // set and add at target aCallback( maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix(fSize, fSize), - interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); + 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); } } @@ -758,7 +758,7 @@ namespace drawinglayer::texture * basegfx::utils::createScaleB2DHomMatrix( 1.0 - (bMTO ? fSize / fAR : fSize), 1.0 - (bMTO ? fSize : fSize * fAR)), - interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); + 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); } } commit 398cd68db0590ada3f59f9cbe2e71869f221eb11 Author: Armin Le Grand (allotropia) <[email protected]> AuthorDate: Fri May 5 16:30:25 2023 +0200 Commit: Andras Timar <[email protected]> CommitDate: Mon May 15 21:38:55 2023 +0200 MCGR: Correct import for Gradient presets/templates Change-Id: I1424ad5deb65f6c72f414a51a40fbd1138c284d8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151432 Tested-by: Jenkins Reviewed-by: Regina Henschel <[email protected]> Reviewed-by: Armin Le Grand <[email protected]> diff --git a/include/xmloff/GradientStyle.hxx b/include/xmloff/GradientStyle.hxx index db946279a238..04ad2832d997 100644 --- a/include/xmloff/GradientStyle.hxx +++ b/include/xmloff/GradientStyle.hxx @@ -23,6 +23,7 @@ #include <sal/config.h> #include <xmloff/dllapi.h> #include <rtl/ustring.hxx> +#include <xmloff/xmlictxt.hxx> class SvXMLImport; class SvXMLExport; @@ -30,6 +31,7 @@ namespace com::sun::star { namespace uno { template<class A> class Reference; } namespace xml::sax { class XFastAttributeList; } namespace uno { class Any; } + namespace awt { struct ColorStop; } } @@ -46,6 +48,15 @@ public: OUString& rStrName ); }; +class XMLOFF_DLLPUBLIC XMLGradientStopContext: public SvXMLImportContext +{ +public: + XMLGradientStopContext( + SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + std::vector<css::awt::ColorStop>& rColorStopVec); + virtual ~XMLGradientStopContext() override; +}; class XMLOFF_DLLPUBLIC XMLGradientStyleExport { diff --git a/svx/source/xml/xmlxtexp.cxx b/svx/source/xml/xmlxtexp.cxx index 3417c7989f5d..bd03967bd832 100644 --- a/svx/source/xml/xmlxtexp.cxx +++ b/svx/source/xml/xmlxtexp.cxx @@ -154,6 +154,7 @@ SvxXMLXTableExportComponent::SvxXMLXTableExportComponent( GetNamespaceMap_().Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW ); GetNamespaceMap_().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK ); GetNamespaceMap_().Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG), XML_NAMESPACE_SVG ); + GetNamespaceMap_().Add( GetXMLToken(XML_NP_LO_EXT), GetXMLToken(XML_N_LO_EXT), XML_NAMESPACE_LO_EXT); SetGraphicStorageHandler(xGraphicStorageHandler); } diff --git a/svx/source/xml/xmlxtimp.cxx b/svx/source/xml/xmlxtimp.cxx index 05e3081f4539..0cb79c981acb 100644 --- a/svx/source/xml/xmlxtimp.cxx +++ b/svx/source/xml/xmlxtimp.cxx @@ -24,8 +24,9 @@ #include <com/sun/star/xml/sax/XDocumentHandler.hpp> #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> #include <com/sun/star/drawing/LineDash.hpp> -#include <com/sun/star/awt/Gradient.hpp> +#include <com/sun/star/awt/Gradient2.hpp> #include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/awt/ColorStop.hpp> #include <com/sun/star/drawing/Hatch.hpp> #include <com/sun/star/io/XSeekable.hpp> #include <comphelper/processfactory.hxx> @@ -46,6 +47,7 @@ #include <svx/xmlgrhlp.hxx> #include <xmlxtimp.hxx> +#include <comphelper/sequence.hxx> #include <comphelper/diagnose_ex.hxx> using namespace com::sun::star; @@ -77,7 +79,6 @@ protected: void importMarker( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName ); void importDash( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName ); void importHatch( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName ); - void importGradient( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName ); void importBitmap( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName ); private: @@ -94,6 +95,93 @@ SvxXMLTableImportContext::SvxXMLTableImportContext( SvXMLImport& rImport, SvxXML { } +namespace +{ + // MCGR: Helper ImportContext to be able to parse sub-content + // entries like XMLGradientStopContext which are allowed now + // for importing Gradients + class XMLGradientHelperContext : public SvXMLImportContext + { + private: + uno::Reference< XNameContainer > mxTable; + css::uno::Any maAny; + OUString maStrName; + std::vector<css::awt::ColorStop> maColorStopVec; + + public: + XMLGradientHelperContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + const css::uno::Reference< XNameContainer >& rxTable); + virtual ~XMLGradientHelperContext() override; + virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& AttrList) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + }; + + XMLGradientHelperContext::XMLGradientHelperContext( + SvXMLImport& rImport, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + const uno::Reference< XNameContainer >& rxTable) + : SvXMLImportContext(rImport), + mxTable(rxTable) + { + try + { + // Import GradientStyle + XMLGradientStyleImport aGradientStyle( GetImport() ); + aGradientStyle.importXML( xAttrList, maAny, maStrName ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("svx"); + } + } + + XMLGradientHelperContext::~XMLGradientHelperContext() + { + // if GradientStyle was imported, add to List + if( !maStrName.isEmpty() && maAny.hasValue() ) + { + if( mxTable->hasByName( maStrName ) ) + { + mxTable->replaceByName( maStrName, maAny ); + } + else + { + mxTable->insertByName( maStrName, maAny ); + } + } + } + + css::uno::Reference<css::xml::sax::XFastContextHandler> XMLGradientHelperContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) + { + // be prepared & import GradientStop entries + if (nElement == XML_ELEMENT(LO_EXT, xmloff::token::XML_GRADIENT_STOP)) + { + return new XMLGradientStopContext(GetImport(), nElement, xAttrList, maColorStopVec); + } + + return nullptr; + } + + void XMLGradientHelperContext::endFastElement(sal_Int32 ) + { + // correcting invalid StopOffset values is done at the model. Therefore we import them here + // without any change. + if (!maColorStopVec.empty()) + { + awt::Gradient2 aGradient; + maAny >>= aGradient; + aGradient.ColorStops = comphelper::containerToSequence(maColorStopVec); + maAny <<= aGradient; + } + } +} + css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLTableImportContext::createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > & rAttrList) @@ -140,6 +228,15 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > } } } + + if (nElement == XML_ELEMENT(DRAW, XML_GRADIENT)) + { + // MCGR: for Gradients, no longer use fixed import but use an own + // ImportContext to be able to import now possible sub-entries like + // ColorStop entries + return new XMLGradientHelperContext( GetImport(), rAttrList, mxTable ); + } + try { rtl::Reference<sax_fastparser::FastAttributeList> xFastList = new sax_fastparser::FastAttributeList(nullptr); @@ -163,12 +260,14 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > case SvxXMLTableImportContextEnum::Hatch: importHatch( xFastList, aAny, aName ); break; - case SvxXMLTableImportContextEnum::Gradient: - importGradient( xFastList, aAny, aName ); - break; case SvxXMLTableImportContextEnum::Bitmap: importBitmap( xFastList, aAny, aName ); break; + default: + // SvxXMLTableImportContextEnum::Gradient + // is no longer imported hee as 'fixed content' + // but dynamicalloy using an own ImportContext + break; } if( !aName.isEmpty() && aAny.hasValue() ) @@ -253,19 +352,6 @@ void SvxXMLTableImportContext::importHatch( const uno::Reference< XFastAttribute } } -void SvxXMLTableImportContext::importGradient( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName ) -{ - try - { - XMLGradientStyleImport aGradientStyle( GetImport() ); - aGradientStyle.importXML( xAttrList, rAny, rName ); - } - catch (const Exception&) - { - TOOLS_WARN_EXCEPTION("svx", ""); - } -} - void SvxXMLTableImportContext::importBitmap( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName ) { try @@ -311,6 +397,9 @@ SvxXMLXTableImport::SvxXMLXTableImport( GetNamespaceMap().Add( "___draw", GetXMLToken(XML_N_DRAW_OOO), XML_NAMESPACE_DRAW ); + GetNamespaceMap().Add( "___loext", + GetXMLToken(XML_N_LO_EXT), + XML_NAMESPACE_LO_EXT); } SvxXMLXTableImport::~SvxXMLXTableImport() noexcept diff --git a/xmloff/source/style/FillStyleContext.cxx b/xmloff/source/style/FillStyleContext.cxx index cae1bcd0313b..3b0ff9ca2ff8 100644 --- a/xmloff/source/style/FillStyleContext.cxx +++ b/xmloff/source/style/FillStyleContext.cxx @@ -104,68 +104,6 @@ bool XMLGradientStyleContext::IsTransient() const return true; } -XMLGradientStopContext::XMLGradientStopContext( - SvXMLImport& rImport, sal_Int32 nElement, - const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, - std::vector<awt::ColorStop>& rColorStopVec) -: SvXMLStyleContext(rImport) -{ - if(nElement != XML_ELEMENT(LO_EXT, xmloff::token::XML_GRADIENT_STOP)) - return; - - double fOffset = -1.0; - OUString sColorType; - OUString sColorValue; - // First collect all attributes - for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) - { - switch(aIter.getToken()) - { - case XML_ELEMENT(SVG, xmloff::token::XML_OFFSET): // needed?? - case XML_ELEMENT(SVG_COMPAT, xmloff::token::XML_OFFSET): - if (!::sax::Converter::convertDouble(fOffset, aIter.toView())) - return; - break; - case XML_ELEMENT(LO_EXT, xmloff::token::XML_COLOR_VALUE): - sColorValue = aIter.toString(); - if (sColorValue.isEmpty()) - return; - break; - case XML_ELEMENT(LO_EXT, xmloff::token::XML_COLOR_TYPE): - sColorType = aIter.toString(); - if (sColorType.isEmpty()) - return; - break; - default: - XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); - } - } - - // As of LO 7.6.0 only "rgb" is implemented. - if (sColorType != u"rgb") - return; - - // Type "rgb" requires kind color-value="#rrggbb". - ::Color aColor; - if (!::sax::Converter::convertColor(aColor, sColorValue)) - return; - - // All attribute values OK. Generate ColorStop. - css::rendering::RGBColor aRGBColor; - aRGBColor.Red = aColor.GetRed() / 255.0; - aRGBColor.Green = aColor.GetGreen() / 255.0; - aRGBColor.Blue = aColor.GetBlue() / 255.0; - - awt::ColorStop aColorStop; - aColorStop.StopOffset = fOffset; - aColorStop.StopColor = aRGBColor; - rColorStopVec.push_back(aColorStop); -} - -XMLGradientStopContext::~XMLGradientStopContext() -{ -} - XMLHatchStyleContext::XMLHatchStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) : SvXMLStyleContext(rImport) diff --git a/xmloff/source/style/FillStyleContext.hxx b/xmloff/source/style/FillStyleContext.hxx index aee8f6d81038..e3d00ad82486 100644 --- a/xmloff/source/style/FillStyleContext.hxx +++ b/xmloff/source/style/FillStyleContext.hxx @@ -51,18 +51,6 @@ public: virtual bool IsTransient() const override; }; -class XMLGradientStopContext: public SvXMLStyleContext -{ -private: - -public: - - XMLGradientStopContext(SvXMLImport& rImport, sal_Int32 nElement, - const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, - std::vector<css::awt::ColorStop>& rColorStopVec); - virtual ~XMLGradientStopContext() override; -}; - // draw:hatch context class XMLHatchStyleContext: public SvXMLStyleContext diff --git a/xmloff/source/style/GradientStyle.cxx b/xmloff/source/style/GradientStyle.cxx index 9f2723078a89..3ab6c422b2c8 100644 --- a/xmloff/source/style/GradientStyle.cxx +++ b/xmloff/source/style/GradientStyle.cxx @@ -145,6 +145,68 @@ void XMLGradientStyleImport::importXML( } } +XMLGradientStopContext::XMLGradientStopContext( + SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + std::vector<awt::ColorStop>& rColorStopVec) +: SvXMLImportContext(rImport) +{ + if(nElement != XML_ELEMENT(LO_EXT, xmloff::token::XML_GRADIENT_STOP)) + return; + + double fOffset = -1.0; + OUString sColorType; + OUString sColorValue; + // First collect all attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, xmloff::token::XML_OFFSET): // needed?? + case XML_ELEMENT(SVG_COMPAT, xmloff::token::XML_OFFSET): + if (!::sax::Converter::convertDouble(fOffset, aIter.toView())) + return; + break; + case XML_ELEMENT(LO_EXT, xmloff::token::XML_COLOR_VALUE): + sColorValue = aIter.toString(); + if (sColorValue.isEmpty()) + return; + break; + case XML_ELEMENT(LO_EXT, xmloff::token::XML_COLOR_TYPE): + sColorType = aIter.toString(); + if (sColorType.isEmpty()) + return; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + // As of LO 7.6.0 only "rgb" is implemented. + if (sColorType != u"rgb") + return; + + // Type "rgb" requires kind color-value="#rrggbb". + ::Color aColor; + if (!::sax::Converter::convertColor(aColor, sColorValue)) + return; + + // All attribute values OK. Generate ColorStop. + css::rendering::RGBColor aRGBColor; + aRGBColor.Red = aColor.GetRed() / 255.0; + aRGBColor.Green = aColor.GetGreen() / 255.0; + aRGBColor.Blue = aColor.GetBlue() / 255.0; + + awt::ColorStop aColorStop; + aColorStop.StopOffset = fOffset; + aColorStop.StopColor = aRGBColor; + rColorStopVec.push_back(aColorStop); +} + +XMLGradientStopContext::~XMLGradientStopContext() +{ +} + // Export XMLGradientStyleExport::XMLGradientStyleExport( commit caa424e6c77993dd0ac1325c20cc5068a1ed8e9a Author: Regina Henschel <[email protected]> AuthorDate: Wed Apr 5 18:10:55 2023 +0200 Commit: Andras Timar <[email protected]> CommitDate: Mon May 15 21:38:55 2023 +0200 WIP ODF import and export for MCGR Current state uses: Element loext:gradient-stop with the attributes svg:offset, loext:color-type with value 'rgb', and loext:color-value with values of kind #rrggbb. Element loext:opacity-stop with the attributes svg:offset and svg:stop-opacity, both with datatype double. With MCGR enabled testColorGradientWithTransparencyDOCX in CppunitTest_chart_export3 has the value 90000 instead of 90196. That is same value as in original file. Thus I have adapted the test. Change-Id: I976934f9b8fb79be4f74adb180b3285486dce31f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150060 Tested-by: Jenkins Reviewed-by: Armin Le Grand <[email protected]> diff --git a/chart2/qa/extras/chart2export3.cxx b/chart2/qa/extras/chart2export3.cxx index dd081f8e5b9b..2fbb976a5d66 100644 --- a/chart2/qa/extras/chart2export3.cxx +++ b/chart2/qa/extras/chart2export3.cxx @@ -203,7 +203,7 @@ void Chart2ExportTest3::testColorGradientWithTransparencyDOCX() // Test the transparency of the first color assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser/c:spPr/a:gradFill/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", "val", "60000"); // Test the transparency of the second color - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser/c:spPr/a:gradFill/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "90196"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser/c:spPr/a:gradFill/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "90000"); } void Chart2ExportTest3::testColorGradientWithTransparencyODS() diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index a37af4acea75..5ea72f7df658 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -3517,6 +3517,11 @@ namespace xmloff::token { XML_MAY_BREAK_BETWEEN_PAGES, + XML_GRADIENT_STOP, // multi-color-gradient + XML_OPACITY_STOP, + XML_COLOR_VALUE, + XML_COLOR_TYPE, + XML_TOKEN_END }; diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index 5029a203bd18..4eb287249809 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -1912,7 +1912,28 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:interleave> </rng:define> - </rng:include> + <!-- Belongs to project MCGR (Armin Le Grand) LO 7.6 --> + <rng:define name="draw-gradient"> + <rng:element name="draw:gradient"> + <rng:ref name="common-draw-gradient-attlist"/> + <rng:ref name="draw-gradient-attlist"/> + <rng:zeroOrMore> + <rng:ref name="loext-gradient-stop"/> + </rng:zeroOrMore> + </rng:element> + </rng:define> + <!-- Belongs to project MCGR (Armin Le Grand) LO 7.6 --> + <rng:define name="draw-opacity"> + <rng:element name="draw:opacity"> + <rng:ref name="common-draw-gradient-attlist"/> + <rng:ref name="draw-opacity-attlist"/> + <rng:zeroOrMore> + <rng:ref name="loext-opacity-stop"/> + </rng:zeroOrMore> + </rng:element> + </rng:define> + + </rng:include> <!-- TODO no proposal --> <rng:define name="loext-p"> @@ -3468,4 +3489,53 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:optional> </rng:define> + <!-- Belongs to project MCGR (Armin Le Grand) LO 7.6 + Intended to be used for theme colors too --> + <rng:define name="common-complex-color-attributes"> + <rng:choice> + <rng:group> + <rng:attribute name="loext:color-type"> + <rng:value>rgb</rng:value> + </rng:attribute> + <rng:attribute name="loext:color-value"> + <rng:ref name="color"/> + </rng:attribute> + </rng:group> + <rng:group> + <rng:attribute name="loext:color-type"> + <rng:value>theme</rng:value> + </rng:attribute> + <rng:attribute name="loext:color-value"> + <!-- will become <rng:ref name="themeColorId"/> + when theme color related attributes are renamed --> + <rng:ref name="theme-color"/> + </rng:attribute> + </rng:group> + </rng:choice> + </rng:define> + + <!-- Belongs to project MCGR (Armin Le Grand) LO 7.6 --> + <rng:define name="loext-gradient-stop"> + <rng:element name="loext:gradient-stop"> + <rng:attribute name="svg:offset"> + <rng:ref name="zeroToOneDecimal"/> + </rng:attribute> + <rng:ref name="common-complex-color-attributes"/> + <rng:empty/> + </rng:element> + </rng:define> + + <!-- Belongs to project MCGR (Armin Le Grand) LO 7.6 --> + <rng:define name="loext-opacity-stop"> + <rng:element name="loext:opacity-stop"> + <rng:attribute name="svg:offset"> + <rng:ref name="zeroToOneDecimal"/> + </rng:attribute> + <rng:attribute name="svg:stop-opacity"> + <rng:ref name="zeroToOneDecimal"/> + </rng:attribute> + <rng:empty/> + </rng:element> + </rng:define> + </rng:grammar> diff --git a/xmloff/qa/unit/data/MCGR_OldToNew.odg b/xmloff/qa/unit/data/MCGR_OldToNew.odg new file mode 100644 index 000000000000..7db627d0c23b Binary files /dev/null and b/xmloff/qa/unit/data/MCGR_OldToNew.odg differ diff --git a/xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg b/xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg new file mode 100644 index 000000000000..8b64a9037e73 Binary files /dev/null and b/xmloff/qa/unit/data/MCGR_OldToNew_opacity.odg differ diff --git a/xmloff/qa/unit/data/MCGR_threeStops.fodt b/xmloff/qa/unit/data/MCGR_threeStops.fodt new file mode 100644 index 000000000000..ac9c9978e299 --- /dev/null +++ b/xmloff/qa/unit/data/MCGR_threeStops.fodt @@ -0,0 +1,317 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:ooow="http://openoffice.org/200 4/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns :css3t="http://www.w3.org/TR/css3-text/" xmlns:officeooo="http://openoffice.org/2009/office" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:initial-creator>Regina Henschel</meta:initial-creator><meta:creation-date>2023-04-18T23:09:21.434000000</meta:creation-date><dc:date>2023-04-18T23:28:52.397000000</dc:date><dc:creator>Regina Henschel</dc:creator><meta:editing-duration>PT9M47S</meta:editing-duration><meta:editing-cycles>3</meta:editing-cycles><meta:generator>B2020/7.6.0.0.alpha0$Windows_X86_64 LibreOffice_project/bcf20273b7036cae9b58d8f452933c0c8d0b8e47</meta:generator><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="1" meta:word-count="1" meta:character-count="5" meta:non-whitespace-character-count="5"/></office:meta> + <office:settings> + <config:config-item-set config:name="ooo:view-settings"> + <config:config-item config:name="ViewAreaTop" config:type="long">0</config:config-item> + <config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item> + <config:config-item config:name="ViewAreaWidth" config:type="long">27349</config:config-item> + <config:config-item config:name="ViewAreaHeight" config:type="long">9527</config:config-item> + <config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item> + <config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item> + <config:config-item-map-indexed config:name="Views"> + <config:config-item-map-entry> + <config:config-item config:name="ViewId" config:type="string">view2</config:config-item> + <config:config-item config:name="ViewLeft" config:type="long">6562</config:config-item> + <config:config-item config:name="ViewTop" config:type="long">2501</config:config-item> + <config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item> + <config:config-item config:name="VisibleTop" config:type="long">0</config:config-item> + <config:config-item config:name="VisibleRight" config:type="long">27347</config:config-item> + <config:config-item config:name="VisibleBottom" config:type="long">9525</config:config-item> + <config:config-item config:name="ZoomType" config:type="short">0</config:config-item> + <config:config-item config:name="ViewLayoutColumns" config:type="short">1</config:config-item> + <config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item> + <config:config-item config:name="ZoomFactor" config:type="short">100</config:config-item> + <config:config-item config:name="IsSelectedFrame" config:type="boolean">true</config:config-item> + <config:config-item config:name="KeepRatio" config:type="boolean">false</config:config-item> + <config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item> + <config:config-item config:name="LegacySingleLineFontwork" config:type="boolean">false</config:config-item> + <config:config-item config:name="ConnectorUseSnapRect" config:type="boolean">false</config:config-item> + <config:config-item config:name="IgnoreBreakAfterMultilineField" config:type="boolean">false</config:config-item> + </config:config-item-map-entry> + </config:config-item-map-indexed> + </config:config-item-set> + <config:config-item-set config:name="ooo:configuration-settings"> + <config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrinterSetup" config:type="base64Binary"/> + <config:config-item config:name="AddParaTableSpacing" config:type="boolean">false</config:config-item> + <config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item> + <config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item> + <config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item> + <config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item> + <config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item> + <config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item> + <config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item> + <config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrinterName" config:type="string"/> + <config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item> + <config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/> + <config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrinterPaperFromSetup" config:type="boolean">false</config:config-item> + <config:config-item config:name="BackgroundParaOverDrawings" config:type="boolean">false</config:config-item> + <config:config-item config:name="CurrentDatabaseCommand" config:type="string"/> + <config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item> + <config:config-item config:name="DisableOffPagePositioning" config:type="boolean">false</config:config-item> + <config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item> + <config:config-item config:name="SaveThumbnail" config:type="boolean">true</config:config-item> + <config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item> + <config:config-item config:name="StylesNoDefault" config:type="boolean">false</config:config-item> + <config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item> + <config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/> + <config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item> + <config:config-item config:name="EmbeddedDatabaseName" config:type="string"/> + <config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item> + <config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item> + <config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item> + <config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item> + <config:config-item config:name="AddVerticalFrameOffsets" config:type="boolean">false</config:config-item> + <config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item> + <config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item> + <config:config-item config:name="HeaderSpacingBelowLastPara" config:type="boolean">false</config:config-item> + <config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item> + <config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item> + <config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item> + <config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item> + <config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item> + <config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item> + <config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">false</config:config-item> + <config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item> + <config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">true</config:config-item> + <config:config-item config:name="AddParaLineSpacingToTableCells" config:type="boolean">false</config:config-item> + <config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item> + <config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item> + <config:config-item config:name="EmbedSystemFonts" config:type="boolean">false</config:config-item> + <config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">true</config:config-item> + <config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item> + <config:config-item config:name="FloattableNomargins" config:type="boolean">false</config:config-item> + <config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item> + <config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item> + <config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item> + <config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item> + <config:config-item config:name="Rsid" config:type="int">447710</config:config-item> + <config:config-item config:name="RsidRoot" config:type="int">238319</config:config-item> + <config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item> + <config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item> + <config:config-item config:name="MsWordCompMinLineHeightByFly" config:type="boolean">false</config:config-item> + <config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item> + <config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item> + <config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item> + <config:config-item config:name="EmbedComplexScriptFonts" config:type="boolean">true</config:config-item> + <config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item> + <config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item> + <config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item> + <config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item> + <config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item> + <config:config-item config:name="TabOverSpacing" config:type="boolean">false</config:config-item> + <config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item> + <config:config-item config:name="SurroundTextWrapSmall" config:type="boolean">false</config:config-item> + <config:config-item config:name="PropLineSpacingShrinksFirstLine" config:type="boolean">true</config:config-item> + <config:config-item config:name="SubtractFlysAnchoredAtFlys" config:type="boolean">false</config:config-item> + <config:config-item config:name="EmptyDbFieldHidesPara" config:type="boolean">true</config:config-item> + <config:config-item config:name="ContinuousEndnotes" config:type="boolean">false</config:config-item> + <config:config-item config:name="ProtectBookmarks" config:type="boolean">false</config:config-item> + <config:config-item config:name="ProtectFields" config:type="boolean">false</config:config-item> + <config:config-item config:name="FrameAutowidthWithMorePara" config:type="boolean">false</config:config-item> + <config:config-item config:name="GutterAtTop" config:type="boolean">false</config:config-item> + <config:config-item config:name="FootnoteInColumnToPageEnd" config:type="boolean">true</config:config-item> + <config:config-item config:name="ImagePreferredDPI" config:type="int">0</config:config-item> + <config:config-item config:name="AutoFirstLineIndentDisregardLineSpace" config:type="boolean">true</config:config-item> + <config:config-item config:name="HyphenateURLs" config:type="boolean">false</config:config-item> + <config:config-item config:name="WordLikeWrapForAsCharFlys" config:type="boolean">false</config:config-item> + <config:config-item config:name="NoNumberingShowFollowBy" config:type="boolean">false</config:config-item> + <config:config-item config:name="DropCapPunctuation" config:type="boolean">true</config:config-item> + <config:config-item config:name="UseVariableWidthNBSP" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item> + <config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrintEmptyPages" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrintFaxName" config:type="string"/> + <config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item> + <config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item> + </config:config-item-set> + </office:settings> + <office:scripts> + <office:script script:language="ooo:Basic"> + <ooo:libraries xmlns:ooo="http://openoffice.org/2004/office" xmlns:xlink="http://www.w3.org/1999/xlink"> + <ooo:library-embedded ooo:name="Standard"/> + </ooo:libraries> + </office:script> + </office:scripts> + <office:font-face-decls> + <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Lucida Sans" svg:font-family="'Lucida Sans'" style:font-family-generic="swiss"/> + <style:font-face style:name="Lucida Sans1" svg:font-family="'Lucida Sans'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Microsoft YaHei" svg:font-family="'Microsoft YaHei'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="NSimSun" svg:font-family="NSimSun" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <draw:gradient draw:name="threeStops" draw:style="square" draw:cx="0%" draw:cy="50%" draw:start-color="#ff0000" draw:end-color="#ffff00" draw:start-intensity="100%" draw:end-intensity="100%" draw:angle="45deg" draw:border="10%"> + <loext:gradient-stop svg:offset="0" loext:color-type="rgb" loext:color-value="#ff0000"/> + <loext:gradient-stop svg:offset="0.3" loext:color-type="rgb" loext:color-value="#0099bb"/> + <loext:gradient-stop svg:offset="1" loext:color-type="rgb" loext:color-value="#ffff00"/></draw:gradient> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="3mm" draw:shadow-offset-y="3mm" draw:start-line-spacing-horizontal="2.83mm" draw:start-line-spacing-vertical="2.83mm" draw:end-line-spacing-horizontal="2.83mm" draw:end-line-spacing-vertical="2.83mm" style:writing-mode="lr-tb" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0mm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="12.51mm" style:writing-mode="lr-tb"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text"> + <style:paragraph-properties fo:margin-top="4.23mm" fo:margin-bottom="2.12mm" style:contextual-spacing="false" fo:keep-with-next="always"/> + <style:text-properties style:font-name="Liberation Sans" fo:font-family="'Liberation Sans'" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="14pt" style:font-name-asian="Microsoft YaHei" style:font-family-asian="'Microsoft YaHei'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="14pt" style:font-name-complex="Lucida Sans1" style:font-family-complex="'Lucida Sans'" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text"> + <style:paragraph-properties fo:margin-top="0mm" fo:margin-bottom="2.47mm" style:contextual-spacing="false" fo:line-height="115%"/> + </style:style> + <style:style style:name="List" style:family="paragraph" style:parent-style-name="Text_20_body" style:class="list"> + <style:text-properties style:font-size-asian="12pt" style:font-name-complex="Lucida Sans" style:font-family-complex="'Lucida Sans'" style:font-family-generic-complex="swiss"/> + </style:style> + <style:style style:name="Caption" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"> + <style:paragraph-properties fo:margin-top="2.12mm" fo:margin-bottom="2.12mm" style:contextual-spacing="false" text:number-lines="false" text:line-number="0"/> + <style:text-properties fo:font-size="12pt" fo:font-style="italic" style:font-size-asian="12pt" style:font-style-asian="italic" style:font-name-complex="Lucida Sans" style:font-family-complex="'Lucida Sans'" style:font-family-generic-complex="swiss" style:font-size-complex="12pt" style:font-style-complex="italic"/> + </style:style> + <style:style style:name="Index" style:family="paragraph" style:parent-style-name="Standard" style:class="index"> + <style:paragraph-properties text:number-lines="false" text:line-number="0"/> + <style:text-properties style:font-size-asian="12pt" style:font-name-complex="Lucida Sans" style:font-family-complex="'Lucida Sans'" style:font-family-generic-complex="swiss"/> + </style:style> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" loext:num-list-format="%1%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" loext:num-list-format="%2%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" loext:num-list-format="%3%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" loext:num-list-format="%4%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" loext:num-list-format="%5%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" loext:num-list-format="%6%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" loext:num-list-format="%7%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" loext:num-list-format="%8%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" loext:num-list-format="%9%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" loext:num-list-format="%10%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="4.99mm" style:num-format="1" text:number-position="left" text:increment="5"/> + <style:default-page-layout> + <style:page-layout-properties style:writing-mode="lr-tb" style:layout-grid-standard-mode="true"/> + </style:default-page-layout> + <loext:theme loext:name="Office"> + <loext:color-table loext:name="LibreOffice"> + <loext:color loext:name="dk1" loext:color="#000000"/> + <loext:color loext:name="lt1" loext:color="#ffffff"/> + <loext:color loext:name="dk2" loext:color="#000000"/> + <loext:color loext:name="lt2" loext:color="#ffffff"/> + <loext:color loext:name="accent1" loext:color="#18a303"/> + <loext:color loext:name="accent2" loext:color="#0369a3"/> + <loext:color loext:name="accent3" loext:color="#a33e03"/> + <loext:color loext:name="accent4" loext:color="#8e03a3"/> + <loext:color loext:name="accent5" loext:color="#c99c00"/> + <loext:color loext:name="accent6" loext:color="#c9211e"/> + <loext:color loext:name="hlink" loext:color="#0000ee"/> + <loext:color loext:name="folHlink" loext:color="#551a8b"/> + </loext:color-table> + </loext:theme> + </office:styles> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph"> + <loext:graphic-properties draw:fill="gradient" draw:fill-gradient-name="threeStops" draw:gradient-step-count="64"/> + </style:style> + <style:style style:name="gr1" style:family="graphic"> + <style:graphic-properties draw:stroke="none" draw:fill="gradient" draw:fill-gradient-name="threeStops" draw:gradient-step-count="0" draw:textarea-horizontal-align="justify" draw:textarea-vertical-align="middle" draw:auto-grow-height="false" fo:min-height="40.02mm" fo:min-width="80.01mm" style:run-through="foreground" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" draw:wrap-influence-on-position="once-concurrent" loext:allow-overlap="true" style:flow-with-text="false"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="210.01mm" fo:page-height="148.01mm" style:num-format="1" style:print-orientation="landscape" fo:margin-top="20mm" fo:margin-bottom="20mm" fo:margin-left="20mm" fo:margin-right="20mm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="44" style:layout-grid-base-height="5.5mm" style:layout-grid-ruby-height="0mm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="true" style:layout-grid-display="true" style:layout-grid-base-width="3.7mm" style:layout-grid-snap-to="true" style:footnote-max-height="0mm" loext:margin-gutter="0mm"> + <style:footnote-sep style:width="0.18mm" style:distance-before-sep="1.01mm" style:distance-after-sep="1.01mm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:style style:name="dp1" style:family="drawing-page"> + <style:drawing-page-properties draw:background-size="full"/> + </style:style> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1" draw:style-name="dp1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="Standard"><draw:custom-shape text:anchor-type="paragraph" draw:z-index="0" draw:name="Shape 1" draw:style-name="gr1" draw:text-style-name="P1" svg:width="80mm" svg:height="40.01mm" svg:x="39.71mm" svg:y="12.03mm"> + <text:p/> + <draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:text-areas="0 0 21600 21600" draw:type="pentagon-right" draw:modifiers="10800" draw:enhanced-path="M 0 0 L ?f0 0 21600 10800 ?f0 21600 0 21600 Z N"> + <draw:equation draw:name="f0" draw:formula="$0 "/> + <draw:handle draw:handle-position="$0 top" draw:handle-range-x-minimum="0" draw:handle-range-x-maximum="21600"/> + </draw:enhanced-geometry> + </draw:custom-shape>Dummy</text:p> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/xmloff/qa/unit/style.cxx b/xmloff/qa/unit/style.cxx index 91879e66a818..2d7706bf7b9e 100644 --- a/xmloff/qa/unit/style.cxx +++ b/xmloff/qa/unit/style.cxx @@ -11,8 +11,13 @@ #include <test/unoapixml_test.hxx> -#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/awt/ColorStop.hpp> +#include <com/sun/star/awt/Gradient2.hpp> #include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/rendering/RGBColor.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> #include <officecfg/Office/Common.hxx> @@ -26,6 +31,7 @@ class XmloffStyleTest : public UnoApiXmlTest public: XmloffStyleTest(); void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override; + uno::Reference<drawing::XShape> getShape(sal_uInt8 nShapeIndex); }; XmloffStyleTest::XmloffStyleTest() @@ -38,6 +44,17 @@ void XmloffStyleTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) XmlTestTools::registerODFNamespaces(pXmlXpathCtx); } +uno::Reference<drawing::XShape> XmloffStyleTest::getShape(sal_uInt8 nShapeIndex) +{ + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, + uno::UNO_QUERY_THROW); + uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages()); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW); + uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShapeIndex), + uno::UNO_QUERY_THROW); + return xShape; +} + CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testFillImageBase64) { // Load a flat ODG that has base64-encoded bitmap as a fill style. @@ -316,6 +333,193 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testPosRelTopMargin) } } +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMCGR_OldToNew) +{ + // The file contains a shape with linear gradient fill from red #ff0000 to yellow #ffff00, + // named 'red2yellow' + loadFromURL(u"MCGR_OldToNew.odg"); + + // saveAndReload includes validation and must not fail with the new elements and attributes. + saveAndReload("draw8"); + + // Examine file markup + // For compatibilty the file should still have the old attributes 'start-color' and 'end-color' + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath = "/office:document-styles/office:styles/draw:gradient[@draw:name='red2yellow']"; + assertXPath(pXmlDoc, sPath, "start-color", "#ff0000"); + assertXPath(pXmlDoc, sPath, "end-color", "#ffff00"); + + // And it must have the new 'gradient-stop' elements. + // The prefix 'loext' needs to be adapted, when the element is available in ODF strict. + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "offset", "0"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-type", "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-value", "#ff0000"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "offset", "1"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-type", "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-value", "#ffff00"); + + // Examine reloaded file + uno::Reference<drawing::XShape> xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY); + + // The old properties need to be still available, as they might be used in macros. + OUString sGradientName; + xShapeProperties->getPropertyValue("FillGradientName") >>= sGradientName; + CPPUNIT_ASSERT_EQUAL(OUString(u"red2yellow"), sGradientName); + awt::Gradient2 aGradient; + xShapeProperties->getPropertyValue("FillGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFF0000), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFFFF00), aGradient.EndColor); + + // Test new properties + auto aColorStopSeq = aGradient.ColorStops; + awt::ColorStop aColorStop = aColorStopSeq[0]; + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopColor.Red); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Green); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Blue); + aColorStop = aColorStopSeq[1]; + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopColor.Red); + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopColor.Green); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Blue); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMCGR_OldToNew_opacity) +{ + // The file contains a shape with solid fill and a radial transparency gradient with start 90%, + // end 0%, border 20% and center at 50%|50%. There is only one draw:opacity element in file. + loadFromURL(u"MCGR_OldToNew_opacity.odg"); + + // saveAndReload includes validation and must not fail with the new elements and attributes. + saveAndReload("draw8"); + + // Examine file markup + // For compatibilty the file should still have the old attributes. + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath = "/office:document-styles/office:styles/draw:opacity"; + assertXPath(pXmlDoc, sPath, "start", "10%"); // UI 90% transparency + assertXPath(pXmlDoc, sPath, "end", "100%"); // UI 0% transparency + assertXPath(pXmlDoc, sPath, "border", "20%"); + assertXPath(pXmlDoc, sPath, "cx", "50%"); + assertXPath(pXmlDoc, sPath, "cy", "50%"); + assertXPath(pXmlDoc, sPath, "style", "radial"); + + // And it must have the new 'opacity-stop' elements. + // The prefix 'loext' needs to be adapted, when the element is available in ODF strict. + OString sFirstStop = sPath + "/loext:opacity-stop[1]"; + assertXPath(pXmlDoc, sFirstStop, "offset", "0"); + // Because of converting through color, the grade of opacity is not exact "0.1" + double fOpacity = getXPathContent(pXmlDoc, sFirstStop + "/@svg:stop-opacity").toDouble(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(0.1, fOpacity, 0.002); + + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[2]", "offset", "1"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[2]", "stop-opacity", "1"); + + // Examine reloaded file + uno::Reference<drawing::XShape> xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY); + + // The old properties need to be still available, as they might be used in macros. + awt::Gradient2 aGradient; + xShapeProperties->getPropertyValue("FillTransparenceGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xE5E5E5), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(sal_Int16(20), aGradient.Border); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.XOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.YOffset); + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_RADIAL, aGradient.Style); + + // Test new properties + auto aColorStopSeq = aGradient.ColorStops; + awt::ColorStop aColorStop = aColorStopSeq[0]; + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopOffset); + // Rounding error because of converting through color: 90% => 0.9 * 255 => 229 + // 299.0 / 255.0 = 0.898039215686275 + CPPUNIT_ASSERT_DOUBLES_EQUAL(0.9, aColorStop.StopColor.Red, 0.002); + CPPUNIT_ASSERT_DOUBLES_EQUAL(0.9, aColorStop.StopColor.Green, 0.002); + CPPUNIT_ASSERT_DOUBLES_EQUAL(0.9, aColorStop.StopColor.Blue, 0.002); + aColorStop = aColorStopSeq[1]; + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Red); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Green); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Blue); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMCGR_threeStops) +{ + // The file contains a shape with square gradient fill from red #ff0000 over teal #0099bb to + // yellow #ffff00, named 'threeStops'. It has 45deg rotation, center 0%|50%, border 10%. + loadFromURL(u"MCGR_threeStops.fodt"); + + // saveAndReload includes validation and must not fail with the new elements and attributes. + saveAndReload("draw8"); + + // Examine file markup + // For compatibilty the file should still have the old attributes 'start-color' and 'end-color' + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath = "/office:document-styles/office:styles/draw:gradient[@draw:name='threeStops']"; + assertXPath(pXmlDoc, sPath, "start-color", "#ff0000"); + assertXPath(pXmlDoc, sPath, "end-color", "#ffff00"); + assertXPath(pXmlDoc, sPath, "style", "square"); + assertXPath(pXmlDoc, sPath, "cx", "0%"); + assertXPath(pXmlDoc, sPath, "cy", "50%"); + assertXPath(pXmlDoc, sPath, "angle", "45deg"); + assertXPath(pXmlDoc, sPath, "border", "10%"); + + // And it must have the new 'gradient-stop' elements. + // The prefix 'loext' needs to be adapted, when the element is available in ODF strict. + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "offset", "0"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-type", "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-value", "#ff0000"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "offset", "0.3"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-type", "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-value", "#0099bb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[3]", "offset", "1"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[3]", "color-type", "rgb"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[3]", "color-value", "#ffff00"); + + // Examine reloaded file + uno::Reference<drawing::XShape> xShape(getShape(0)); + CPPUNIT_ASSERT(xShape.is()); + uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY); + + // The old properties need to be still available, as they might be used in macros. + OUString sGradientName; + xShapeProperties->getPropertyValue("FillGradientName") >>= sGradientName; + CPPUNIT_ASSERT_EQUAL(OUString(u"threeStops"), sGradientName); + awt::Gradient2 aGradient; + xShapeProperties->getPropertyValue("FillGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFF0000), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFFFF00), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_SQUARE, aGradient.Style); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aGradient.XOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.YOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(450), aGradient.Angle); + CPPUNIT_ASSERT_EQUAL(sal_Int16(10), aGradient.Border); + + // Test new properties + auto aColorStopSeq = aGradient.ColorStops; + awt::ColorStop aColorStop = aColorStopSeq[0]; + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopColor.Red); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Green); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Blue); + aColorStop = aColorStopSeq[1]; + CPPUNIT_ASSERT_EQUAL(0.3, aColorStop.StopOffset); + // 0x99 = 153 => 153/255 = 0.6, 0xbb = 187 => 187/255 = 0.733... + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Red); + CPPUNIT_ASSERT_EQUAL(0.6, aColorStop.StopColor.Green); + CPPUNIT_ASSERT_DOUBLES_EQUAL(0.733333333333333, aColorStop.StopColor.Blue, 0.0000001); + aColorStop = aColorStopSeq[2]; + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopOffset); + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopColor.Red); + CPPUNIT_ASSERT_EQUAL(1.0, aColorStop.StopColor.Green); + CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Blue); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 17a58c6984d1..a40c27459bef 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -3520,6 +3520,11 @@ namespace xmloff::token { TOKEN("may-break-between-pages", XML_MAY_BREAK_BETWEEN_PAGES), + TOKEN("gradient-stop", XML_GRADIENT_STOP), + TOKEN("opacity-stop", XML_OPACITY_STOP), + TOKEN("color-value", XML_COLOR_VALUE), + TOKEN("color-type", XML_COLOR_TYPE), + #if OSL_DEBUG_LEVEL > 0 { 0, nullptr, std::nullopt, XML_TOKEN_END } #else diff --git a/xmloff/source/style/FillStyleContext.cxx b/xmloff/source/style/FillStyleContext.cxx index 8cd99a25b261..cae1bcd0313b 100644 --- a/xmloff/source/style/FillStyleContext.cxx +++ b/xmloff/source/style/FillStyleContext.cxx @@ -17,21 +17,31 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include "FillStyleContext.hxx" + +#include <TransGradientStyle.hxx> + +#include <com/sun/star/awt/ColorStop.hpp> +#include <com/sun/star/awt/Gradient2.hpp> +#include <com/sun/star/awt/XBitmap.hpp> #include <com/sun/star/container/XNameContainer.hpp> #include <com/sun/star/graphic/XGraphic.hpp> -#include <com/sun/star/awt/XBitmap.hpp> -#include "FillStyleContext.hxx" +#include <com/sun/star/rendering/RGBColor.hpp> + +#include <comphelper/sequence.hxx> +#include <sax/tools/converter.hxx> #include <xmloff/xmlimp.hxx> #include <xmloff/GradientStyle.hxx> #include <xmloff/HatchStyle.hxx> #include <xmloff/ImageStyle.hxx> -#include <TransGradientStyle.hxx> #include <xmloff/MarkerStyle.hxx> #include <xmloff/DashStyle.hxx> #include <xmloff/xmlnamespace.hxx> #include <xmloff/xmltkmap.hxx> #include <xmloff/XMLBase64ImportContext.hxx> +#include <vector> + using namespace ::com::sun::star; @@ -48,10 +58,29 @@ XMLGradientStyleContext::~XMLGradientStyleContext() { } +css::uno::Reference<css::xml::sax::XFastContextHandler> XMLGradientStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if (nElement == XML_ELEMENT(LO_EXT, xmloff::token::XML_GRADIENT_STOP)) + return new XMLGradientStopContext(GetImport(), nElement, xAttrList, maColorStopVec); + + return nullptr; +} + void XMLGradientStyleContext::endFastElement(sal_Int32 ) { - uno::Reference< container::XNameContainer > xGradient( GetImport().GetGradientHelper() ); + // correcting invalid StopOffset values is done at the model. Therefore we import them here + // without any change. + if (!maColorStopVec.empty()) + { + awt::Gradient2 aGradient; + maAny >>= aGradient; + aGradient.ColorStops = comphelper::containerToSequence(maColorStopVec); + maAny <<= aGradient; + } + uno::Reference< container::XNameContainer > xGradient( GetImport().GetGradientHelper() ); try { if(xGradient.is()) @@ -75,6 +104,67 @@ bool XMLGradientStyleContext::IsTransient() const return true; } +XMLGradientStopContext::XMLGradientStopContext( + SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + std::vector<awt::ColorStop>& rColorStopVec) +: SvXMLStyleContext(rImport) +{ + if(nElement != XML_ELEMENT(LO_EXT, xmloff::token::XML_GRADIENT_STOP)) + return; + + double fOffset = -1.0; + OUString sColorType; + OUString sColorValue; + // First collect all attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, xmloff::token::XML_OFFSET): // needed?? + case XML_ELEMENT(SVG_COMPAT, xmloff::token::XML_OFFSET): + if (!::sax::Converter::convertDouble(fOffset, aIter.toView())) + return; + break; + case XML_ELEMENT(LO_EXT, xmloff::token::XML_COLOR_VALUE): + sColorValue = aIter.toString(); + if (sColorValue.isEmpty()) + return; + break; + case XML_ELEMENT(LO_EXT, xmloff::token::XML_COLOR_TYPE): + sColorType = aIter.toString(); + if (sColorType.isEmpty()) + return; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + // As of LO 7.6.0 only "rgb" is implemented. + if (sColorType != u"rgb") + return; + + // Type "rgb" requires kind color-value="#rrggbb". + ::Color aColor; + if (!::sax::Converter::convertColor(aColor, sColorValue)) + return; + + // All attribute values OK. Generate ColorStop. + css::rendering::RGBColor aRGBColor; + aRGBColor.Red = aColor.GetRed() / 255.0; + aRGBColor.Green = aColor.GetGreen() / 255.0; + aRGBColor.Blue = aColor.GetBlue() / 255.0; + + awt::ColorStop aColorStop; + aColorStop.StopOffset = fOffset; + aColorStop.StopColor = aRGBColor; + rColorStopVec.push_back(aColorStop); +} + +XMLGradientStopContext::~XMLGradientStopContext() +{ +} XMLHatchStyleContext::XMLHatchStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) @@ -205,10 +295,30 @@ XMLTransGradientStyleContext::~XMLTransGradientStyleContext() { } +css::uno::Reference<css::xml::sax::XFastContextHandler> XMLTransGradientStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if (nElement == XML_ELEMENT(LO_EXT, xmloff::token::XML_OPACITY_STOP)) + return new XMLTransparencyStopContext(GetImport(), nElement, xAttrList, maColorStopVec); + + return nullptr; +} + void XMLTransGradientStyleContext::endFastElement(sal_Int32 ) { uno::Reference< container::XNameContainer > xTransGradient( GetImport().GetTransGradientHelper() ); + // correcting invalid StopOffset values is done at the model. Therefore we import them here + // without any change. + if (!maColorStopVec.empty()) + { + awt::Gradient2 aGradient; + maAny >>= aGradient; + aGradient.ColorStops = comphelper::containerToSequence(maColorStopVec); + maAny <<= aGradient; + } + try { if(xTransGradient.is()) @@ -232,6 +342,53 @@ bool XMLTransGradientStyleContext::IsTransient() const return true; } +XMLTransparencyStopContext::XMLTransparencyStopContext( + SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + std::vector<awt::ColorStop>& rColorStopVec) +: SvXMLStyleContext(rImport) +{ + if(nElement != XML_ELEMENT(LO_EXT, xmloff::token::XML_OPACITY_STOP)) + return; + + double fOffset = -1.0; + css::rendering::RGBColor aRGBColor; // transparency is handled as gray color + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, xmloff::token::XML_OFFSET): // needed?? + case XML_ELEMENT(SVG_COMPAT, xmloff::token::XML_OFFSET): + if (!::sax::Converter::convertDouble(fOffset, aIter.toView())) + return; + break; + case XML_ELEMENT(SVG, xmloff::token::XML_STOP_OPACITY): + case XML_ELEMENT(SVG_COMPAT, xmloff::token::XML_STOP_OPACITY): + { + double fOpacity = 1.0; + if (!::sax::Converter::convertDouble(fOpacity, aIter.toView())) + return; + // Transparency is gray, full transparent is (1|1|1). + double fGrayComponent = std::clamp<double>(1.0 - fOpacity, 0.0, 1.0); + aRGBColor.Red = fGrayComponent; + aRGBColor.Green = fGrayComponent; + aRGBColor.Blue = fGrayComponent; + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + awt::ColorStop aColorStop; + aColorStop.StopOffset = fOffset; + aColorStop.StopColor = aRGBColor; + rColorStopVec.push_back(aColorStop); +} + +XMLTransparencyStopContext::~XMLTransparencyStopContext() +{ +} XMLMarkerStyleContext::XMLMarkerStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) diff --git a/xmloff/source/style/FillStyleContext.hxx b/xmloff/source/style/FillStyleContext.hxx index 3b17c29c8239..aee8f6d81038 100644 --- a/xmloff/source/style/FillStyleContext.hxx +++ b/xmloff/source/style/FillStyleContext.hxx @@ -19,9 +19,13 @@ #pragma once +#include <com/sun/star/awt/ColorStop.hpp> #include <com/sun/star/io/XOutputStream.hpp> #include <xmloff/xmlstyle.hxx> #include <rtl/ustring.hxx> +#include <sal/types.h> + +#include <vector> // draw:gradient context @@ -30,6 +34,7 @@ class XMLGradientStyleContext: public SvXMLStyleContext private: css::uno::Any maAny; OUString maStrName; + std::vector<css::awt::ColorStop> maColorStopVec; public: @@ -37,11 +42,27 @@ public: const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); virtual ~XMLGradientStyleContext() override; + virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& AttrList) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; virtual bool IsTransient() const override; }; +class XMLGradientStopContext: public SvXMLStyleContext +{ +private: + +public: + + XMLGradientStopContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + std::vector<css::awt::ColorStop>& rColorStopVec); + virtual ~XMLGradientStopContext() override; +}; + // draw:hatch context class XMLHatchStyleContext: public SvXMLStyleContext @@ -91,6 +112,7 @@ class XMLTransGradientStyleContext: public SvXMLStyleContext private: css::uno::Any maAny; OUString maStrName; + std::vector<css::awt::ColorStop> maColorStopVec; // Transparency is handled as color gray. public: @@ -98,11 +120,27 @@ public: const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); virtual ~XMLTransGradientStyleContext() override; + virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& AttrList) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; virtual bool IsTransient() const override; }; +class XMLTransparencyStopContext: public SvXMLStyleContext +{ +private: + +public: + + XMLTransparencyStopContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + std::vector<css::awt::ColorStop>& rColorStopVec); + virtual ~XMLTransparencyStopContext() override; +}; + // draw:marker context class XMLMarkerStyleContext: public SvXMLStyleContext diff --git a/xmloff/source/style/GradientStyle.cxx b/xmloff/source/style/GradientStyle.cxx index 81ccd84d2b55..9f2723078a89 100644 --- a/xmloff/source/style/GradientStyle.cxx +++ b/xmloff/source/style/GradientStyle.cxx @@ -19,22 +19,21 @@ #include <xmloff/GradientStyle.hxx> -#include <com/sun/star/awt/Gradient.hpp> +#include <com/sun/star/awt/Gradient2.hpp> -#include <sax/tools/converter.hxx> #include <comphelper/documentconstants.hxx> - -#include <xmloff/namespacemap.hxx> -#include <xmloff/xmluconv.hxx> -#include <xmloff/xmlnamespace.hxx> -#include <xmloff/xmltoken.hxx> #include <rtl/ustrbuf.hxx> #include <rtl/ustring.hxx> #include <sal/log.hxx> -#include <xmloff/xmltkmap.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlement.hxx> #include <xmloff/xmlexp.hxx> #include <xmloff/xmlimp.hxx> -#include <xmloff/xmlement.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> using namespace ::com::sun::star; using namespace ::xmloff::token; @@ -64,7 +63,7 @@ void XMLGradientStyleImport::importXML( { OUString aDisplayName; - awt::Gradient aGradient; + awt::Gradient2 aGradient; aGradient.Style = css::awt::GradientStyle_LINEAR; aGradient.StartColor = 0; aGradient.EndColor = 0; @@ -158,7 +157,7 @@ void XMLGradientStyleExport::exportXML( const OUString& rStrName, const uno::Any& rValue ) { - awt::Gradient aGradient; + awt::Gradient2 aGradient; if( rStrName.isEmpty() ) return; @@ -230,9 +229,42 @@ void XMLGradientStyleExport::exportXML( aStrValue = aOut.makeStringAndClear(); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); - // Do Write + // ctor writes start tag. End-tag is written by destructor at block end. SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_GRADIENT, true, false ); + + // Write child elements <loext:gradient-stop> + // Do not export in standard ODF 1.3 or older. + if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + return; + sal_Int32 nCount = aGradient.ColorStops.getLength(); + if (nCount == 0) + return; + + double fPreviousOffset = 0.0; + for (auto& aCandidate : aGradient.ColorStops) + { + // Attribute svg:offset. Make sure offsets are increasing. + double fOffset = std::clamp<double>(aCandidate.StopOffset, 0.0, 1.0); + if (fOffset < fPreviousOffset) + fOffset = fPreviousOffset; + rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset)); + fPreviousOffset = fOffset; + + // As of LO 7.6.0 only color-type="rgb" is implemented. + rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_COLOR_TYPE, u"rgb"); + + // Attribute loext:color-value, data type color, that is #rrggbb. + rendering::RGBColor aDecimalColor = aCandidate.StopColor; + ::Color aToolsColor(std::clamp<sal_uInt8>(std::round(aDecimalColor.Red * 255.0), 0, 255), + std::clamp<sal_uInt8>(std::round(aDecimalColor.Green * 255.0), 0, 255), + std::clamp<sal_uInt8>(std::round(aDecimalColor.Blue * 255.0), 0, 255)); + rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_COLOR_VALUE, + rtl::OUStringChar('#') + aToolsColor.AsRGBHexString()); + + // write gradient stop element + SvXMLElementExport aStopElement(rExport, XML_NAMESPACE_LO_EXT, XML_GRADIENT_STOP, true, true); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/TransGradientStyle.cxx b/xmloff/source/style/TransGradientStyle.cxx index 9b000c3eb448..d89348bbe0e8 100644 --- a/xmloff/source/style/TransGradientStyle.cxx +++ b/xmloff/source/style/TransGradientStyle.cxx @@ -19,22 +19,21 @@ #include <TransGradientStyle.hxx> -#include <com/sun/star/awt/Gradient.hpp> +#include <com/sun/star/awt/Gradient2.hpp> -#include <sax/tools/converter.hxx> #include <comphelper/documentconstants.hxx> - -#include <xmloff/namespacemap.hxx> -#include <xmloff/xmluconv.hxx> -#include <xmloff/xmlnamespace.hxx> #include <rtl/ustrbuf.hxx> #include <rtl/ustring.hxx> #include <sal/log.hxx> +#include <sax/tools/converter.hxx> #include <tools/color.hxx> -#include <xmloff/xmltkmap.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlement.hxx> #include <xmloff/xmlexp.hxx> #include <xmloff/xmlimp.hxx> -#include <xmloff/xmlement.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmluconv.hxx> using namespace ::com::sun::star; @@ -65,7 +64,7 @@ void XMLTransGradientStyleImport::importXML( { OUString aDisplayName; - awt::Gradient aGradient; + awt::Gradient2 aGradient; aGradient.XOffset = 0; aGradient.YOffset = 0; aGradient.StartIntensity = 100; @@ -170,7 +169,7 @@ void XMLTransGradientStyleExport::exportXML( const OUString& rStrName, const uno::Any& rValue ) { - awt::Gradient aGradient; + awt::Gradient2 aGradient; if( rStrName.isEmpty() ) return; @@ -237,10 +236,37 @@ void XMLTransGradientStyleExport::exportXML( aStrValue = aOut.makeStringAndClear(); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); - // Do Write + // ctor writes start tag. End-tag is written by destructor at block end. SvXMLElementExport rElem( rExport, XML_NAMESPACE_DRAW, XML_OPACITY, true, false ); + + // Write child elements <loext:opacity-stop> + // Do not export in standard ODF 1.3 or older. + if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + return; + sal_Int32 nCount = aGradient.ColorStops.getLength(); + if (nCount == 0) + return; + double fPreviousOffset = 0.0; + for (auto& aCandidate : aGradient.ColorStops) + { + // Attribute svg:offset. Make sure offsets are increasing. + double fOffset = std::clamp<double>(aCandidate.StopOffset, 0.0, 1.0); + if (fOffset < fPreviousOffset) + fOffset = fPreviousOffset; + rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset)); + fPreviousOffset = fOffset; + + // Attribute svg:stop-opacity, data type zeroToOneDecimal + rendering::RGBColor aDecimalColor = aCandidate.StopColor; + // transparency is encoded as gray, 1.0 corresponds to full transparent + double fOpacity = std::clamp<double>(1.0 - aDecimalColor.Red, 0.0, 1.0); + rExport.AddAttribute(XML_NAMESPACE_SVG, XML_STOP_OPACITY, OUString::number(fOpacity)); + + // write opacity stop element + SvXMLElementExport aStopElement(rExport, XML_NAMESPACE_LO_EXT, XML_OPACITY_STOP, true, true); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 2b5c3c654ef3..401a0ba9dcf5 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -3260,4 +3260,8 @@ alias tag fill-use-slide-background may-break-between-pages +gradient-stop +opacity-stop +color-value +color-type TOKEN_END_DUMMY commit fd6069d8cb4bfedba2f63f4f1839d6739a8299ac Author: Armin Le Grand (allotropia) <[email protected]> AuthorDate: Fri Apr 21 15:18:09 2023 +0200 Commit: Andras Timar <[email protected]> CommitDate: Mon May 15 21:38:55 2023 +0200 MCGR: Make MCGR default for oox im/export, cleanup Following an error in CppunitTest_chart2_export3 I updated the transparency definition at WriteGradientFill and corrected usages. Had to correct/adapt some Chart UnitTests. Some of these changes are temporary since this will/has to change when ODF MCGR im/export is integrated. I checked that all of these cases actually work, comparing im LO and MSO. Adapted some Chart2ImportTest to directly compare/check now for the fully imported tranparence gradient with available higher precision. Adapted OoxDrawingmlTest testGradientMultiStepTransparency to use new MCGR capabilities. Adapted testTextframeGradient and tested the turn-around with rtf gradients. These are a little bit limited and needed some extra care. Adapted testTextframeGradient. Adapted SdOOXMLExportTest1, testTdf94238 Adapted SdOOXMLExportTest1, testTdf128345GradientAxial Adapted SdOOXMLExportTest2, testTdf105739 Adapted SdOOXMLExportTest3, testTdf127372 Adapted SdOOXMLExportTest3, testTdf127379 Adapted SdMiscTest, testFillGradient Adapted testTextframeGradient Adapted ScFiltersTest3, testTdf129789 Adapted SdUiImpressTest, testPageFillGradient Adapted SdOOXMLExportTest1, testTdf128345GradientLinear by using better double-to-integer rounding (basegfx::fround) in DrawingML::WriteGradientStop. After double calculations this makes the tansition to integer correct and stable. Also took back change at testTdf128345ChartArea_CG_TS_export which showed the same flaw before. 2nd look @testTdf128345Legend_CS_TG_axial_export made me add that stuff again and adapt the axial ColorStop adding in the export to not export the middle enty twice. Extended test a little bit, too. Only do not add value if it starts at 0.0 aka StartColor, else adding it is corect. Adapted some tests CPPUNIT_ASSERT to CPPUNIT_ASSERT_EQUAL after being pointed to it from gerrit_linux_clang_dbgutil build. Change-Id: I4a993053da8960035671b655e67908f36e59b5fe Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150763 Tested-by: Jenkins Reviewed-by: Armin Le Grand <[email protected]> diff --git a/chart2/qa/extras/chart2geometry.cxx b/chart2/qa/extras/chart2geometry.cxx index bab696a15e9b..497f9a099755 100644 --- a/chart2/qa/extras/chart2geometry.cxx +++ b/chart2/qa/extras/chart2geometry.cxx @@ -175,6 +175,12 @@ void Chart2GeometryTest::testTdf128345ChartArea_CG_TS_export() // Without the patch the transparency was lost in saved pptx file. loadFromURL(u"odp/tdf128345_ChartArea_CG_TS.odp"); + // MCGR: Similar to testTdf128345Legend_CS_TG_axial_export: + // Checked that it works with the existing import file, + // but will change with ODF MCGR im/export again. + // Adapting for now, but need to re-check values after + // ODF im/export for MCGR is integrated + // Make sure the chart area has a transparency in gradient stops in saved pptx file. xmlDocUniquePtr pXmlDoc = parseExport("ppt/charts/chart", "Impress MS PowerPoint 2007 XML"); CPPUNIT_ASSERT(pXmlDoc); @@ -192,6 +198,12 @@ void Chart2GeometryTest::testTdf128345ChartArea_CG_TS_import() // Make sure chart area has transparency when pptx document is opened and resaved as odp. // As of Aug 2020, the import generates a transparency gradient. When import is changed to // generate solid transparency, the test needs to be adapted. + + // MCGR: Similar to testTdf128345Legend_CS_TG_axial_export: + // Checked that it works with the existing import file, + // but will change with ODF MCGR im/export again. We will need to + // update the *.odp input file. Disable unclear values for now and + // adapt when ODF im/export for MCGR is integrated loadFromURL(u"pptx/tdf128345_ChartArea_CG_TS.pptx"); // Find transparency gradient name @@ -218,7 +230,7 @@ void Chart2GeometryTest::testTdf128345ChartArea_CG_TS_import() assertXPath(pXmlDoc2, sStart + " and @draw:start='30%']"); assertXPath(pXmlDoc2, sStart + " and @draw:end='30%']"); assertXPath(pXmlDoc2, sStart + " and @draw:angle='30deg']"); - assertXPath(pXmlDoc2, sStart + " and @draw:border='20%']"); + assertXPath(pXmlDoc2, sStart + " and @draw:border='0%']"); // MCGR: no border anymore 20% -> 0% } void Chart2GeometryTest::testTdf128345ChartWall_CS_TG_export() @@ -281,13 +293,21 @@ void Chart2GeometryTest::testTdf128345Legend_CS_TG_axial_export() CPPUNIT_ASSERT(pXmlDoc); OString sPathStart("//c:chartSpace/c:chart/c:legend/c:spPr/a:gradFill"); - assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs", 3); // axial - // no element for 0% transparent + + // MCGR: three entries due to axial being mirrored+expanded to linear + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs", 3); + + // MCGR: start entry, no transparence, pos zero assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", 0); - // 100% transparent = opacity 0. It comes from "axial", therefore it is in the middle. + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]", "pos", "0"); + + // MCGR: middle entry, 100% transparence, pos 0.5 assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "0"); assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]", "pos", "50000"); + + // MCGR: end entry, no transparence, pos 1.0 assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[3]/a:srgbClr/a:alpha", 0); + assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[3]", "pos", "100000"); } void Chart2GeometryTest::testTdf128345Legend_CS_TG_axial_import() @@ -316,8 +336,9 @@ void Chart2GeometryTest::testTdf128345Legend_CS_TG_axial_import() const OString sAttribute("@draw:name='" + OU2O(sOUOpacityName) + "'"); const OString sStart("//office:document-styles/office:styles/draw:opacity[" + sAttribute); assertXPath(pXmlDoc2, sStart + "]", 1); - assertXPath(pXmlDoc2, sStart + " and @draw:style='axial']"); - assertXPath(pXmlDoc2, sStart + " and @draw:start='0%']"); + // MCGR: Needs odf im/export for MCGR, then adapt. + assertXPath(pXmlDoc2, sStart + " and @draw:style='linear']"); // MCGR: axial -> linear + assertXPath(pXmlDoc2, sStart + " and @draw:start='100%']"); // MCGR: 0% -> 100% assertXPath(pXmlDoc2, sStart + " and @draw:end='100%']"); } diff --git a/chart2/qa/extras/chart2import.cxx b/chart2/qa/extras/chart2import.cxx index a9c301a94b93..e309fa912c3a 100644 --- a/chart2/qa/extras/chart2import.cxx +++ b/chart2/qa/extras/chart2import.cxx @@ -32,8 +32,9 @@ #include <iterator> #include <com/sun/star/util/Color.hpp> -#include <com/sun/star/awt/Gradient.hpp> +#include <com/sun/star/awt/Gradient2.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <basegfx/utils/gradienttools.hxx> class Chart2ImportTest : public ChartTest { @@ -798,12 +799,23 @@ void Chart2ImportTest::testBnc889755() //tdf#139940 - the title's gradient was lost and was filled with solid blue, instead of a "blue underline". uno::Reference<drawing::XDrawPagesSupplier> xDoc(mxComponent, uno::UNO_QUERY_THROW); uno::Reference<drawing::XDrawPage> xPage(xDoc->getDrawPages()->getByIndex(0), uno::UNO_QUERY_THROW); + // Shape "Title 3" + // MCGR: Use the whole completely imported transparency gradient to check for correctness uno::Reference<beans::XPropertySet> xShapeProps(xPage->getByIndex(4), uno::UNO_QUERY_THROW); - awt::Gradient aTransparence; + awt::Gradient2 aTransparence; xShapeProps->getPropertyValue("FillTransparenceGradient") >>= aTransparence; - CPPUNIT_ASSERT(aTransparence.StartColor != aTransparence.EndColor); - CPPUNIT_ASSERT_EQUAL(COL_WHITE, Color(ColorTransparency, aTransparence.StartColor)); + + basegfx::ColorStops aColorStops; + basegfx::utils::fillColorStopsFromGradient2(aColorStops, aTransparence); + + CPPUNIT_ASSERT_EQUAL(size_t(3), aColorStops.size()); + CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[0].getStopOffset(), 0.0)); + CPPUNIT_ASSERT_EQUAL(aColorStops[0].getStopColor(), basegfx::BColor(0.25, 0.25, 0.25)); + CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 0.070000000000000007)); + CPPUNIT_ASSERT_EQUAL(aColorStops[1].getStopColor(), basegfx::BColor(0.25, 0.25, 0.25)); + CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[2].getStopOffset(), 0.080000000000000002)); + CPPUNIT_ASSERT_EQUAL(aColorStops[2].getStopColor(), basegfx::BColor(1.0, 1.0, 1.0)); } void Chart2ImportTest::testBnc882383() @@ -832,14 +844,22 @@ void Chart2ImportTest::testTransparencyGradientValue() xPropertySet->getPropertyValue("FillTransparenceGradientName") >>= sTranspGradientName; CPPUNIT_ASSERT(!sTranspGradientName.isEmpty()); - awt::Gradient aTransparenceGradient; + awt::Gradient2 aTransparenceGradient; uno::Reference< lang::XMultiServiceFactory > xFact(xChartDoc, uno::UNO_QUERY); CPPUNIT_ASSERT(xFact.is()); uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY); uno::Any rTransparenceValue = xTransparenceGradient->getByName(sTranspGradientName); CPPUNIT_ASSERT(rTransparenceValue >>= aTransparenceGradient); - CPPUNIT_ASSERT_EQUAL(sal_Int32(3355443), aTransparenceGradient.EndColor); - CPPUNIT_ASSERT_EQUAL(sal_Int32(5000268), aTransparenceGradient.StartColor); + + basegfx::ColorStops aColorStops; + basegfx::utils::fillColorStopsFromGradient2(aColorStops, aTransparenceGradient); + + // MCGR: Use the whole completely imported transparency gradient to check for correctness + CPPUNIT_ASSERT_EQUAL(size_t(2), aColorStops.size()); + CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[0].getStopOffset(), 0.0)); + CPPUNIT_ASSERT_EQUAL(aColorStops[0].getStopColor(), basegfx::BColor(0.3, 0.3, 0.3)); + CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 1.0)); + CPPUNIT_ASSERT_EQUAL(aColorStops[1].getStopColor(), basegfx::BColor(0.2, 0.2, 0.2)); } void Chart2ImportTest::testSimpleStrictXLSX() diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index e70696403ef1..f7bd91669a1d 100644 ... etc. - the rest is truncated
