basegfx/source/tools/bgradient.cxx | 206 basegfx/source/tools/gradienttools.cxx | 99 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 205 drawinglayer/source/tools/emfphelperdata.cxx | 56 drawinglayer/source/tools/emfphelperdata.hxx | 2 drawinglayer/source/tools/emfppath.cxx | 126 drawinglayer/source/tools/emfppath.hxx | 5 emfio/qa/cppunit/emf/EmfImportTest.cxx | 186 emfio/qa/cppunit/emf/data/TestEmfPlusFillClosedCurve.emf |binary emfio/qa/cppunit/emf/data/TestEmfPlusRecordTypeDrawCurve.emf |binary include/basegfx/utils/bgradient.hxx | 29 include/basegfx/utils/gradienttools.hxx | 21 include/svx/sdr/contact/viewobjectcontact.hxx | 3 include/xmloff/GradientStyle.hxx | 4 include/xmloff/HatchStyle.hxx | 4 oox/source/drawingml/fillproperties.cxx | 97 oox/source/export/drawingml.cxx | 61 readlicense_oo/license/CREDITS.fodt | 3438 +++++------ sc/qa/uitest/calc_tests9/tdf154174.py | 35 sc/source/core/data/column3.cxx | 23 sc/source/core/data/conditio.cxx | 2 sc/source/core/data/dociter.cxx | 6 sc/source/ui/view/viewfunc.cxx | 2 sd/source/ui/dlg/navigatr.cxx | 1 sd/source/ui/dlg/sdtreelb.cxx | 35 svtools/source/misc/sampletext.cxx | 5 svx/source/sdr/contact/viewobjectcontact.cxx | 11 svx/source/xoutdev/xattr.cxx | 7 sw/qa/extras/htmlexport/data/listsWithNumFormat.fodt | 74 sw/qa/extras/htmlexport/data/tableRight.fodt | 22 sw/qa/extras/htmlexport/htmlexport.cxx | 31 sw/qa/extras/uiwriter/data/pageBreakWithPageStyle.fodt | 17 sw/qa/extras/uiwriter/uiwriter8.cxx | 32 sw/qa/extras/ww8export/data/tdf104704_mangledFooter.odt |binary sw/qa/extras/ww8export/ww8export4.cxx | 5 sw/source/core/doc/docfmt.cxx | 60 sw/source/core/doc/notxtfrm.cxx | 3 sw/source/core/text/porlay.cxx | 24 sw/source/filter/html/htmlnumwriter.cxx | 5 sw/source/filter/html/htmltabw.cxx | 19 sw/source/filter/ww8/ww8atr.cxx | 5 sw/source/uibase/uiview/viewmdi.cxx | 13 vcl/inc/osx/a11ywrapper.h | 3 vcl/osx/a11ytextattributeswrapper.mm | 1 vcl/osx/a11ywrapper.mm | 72 vcl/osx/salframeview.mm | 8 vcl/qa/cppunit/pdfexport/data/tdf155190.odt |binary vcl/qa/cppunit/pdfexport/pdfexport.cxx | 96 vcl/quartz/salgdi.cxx | 6 vcl/source/gdi/CommonSalLayout.cxx | 2 vcl/source/gdi/impglyphitem.cxx | 5 vcl/source/gdi/sallayout.cxx | 13 vcl/source/outdev/font.cxx | 8 xmloff/qa/unit/data/MCGR_Border_restoration.pptx |binary xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx |binary xmloff/qa/unit/style.cxx | 76 xmloff/source/style/GradientStyle.cxx | 116 xmloff/source/style/HatchStyle.cxx | 26 xmloff/source/style/TransGradientStyle.cxx | 72 59 files changed, 3224 insertions(+), 2259 deletions(-)
New commits: commit dd2c45a12218f63be5121ce113a0e75bd317aba1 Author: Regina Henschel <rb.hensc...@t-online.de> AuthorDate: Thu Jun 1 19:01:00 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:12 2023 +0200 MCGR: Use tryToRecreateBorder too for transparency This is similar to 'Use tryToRecreateBorder for better BW comp with LO' (see commit 8259a99f41367a1d8326c9157fe1902915715879), but now for transparency gradients. Change-Id: I1c2e11562fa998c364896d517f4ed3bfe92f6c15 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152508 Tested-by: Jenkins Reviewed-by: Regina Henschel <rb.hensc...@t-online.de> diff --git a/xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx b/xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx new file mode 100644 index 000000000000..f32c4d5e2b21 Binary files /dev/null and b/xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx differ diff --git a/xmloff/qa/unit/style.cxx b/xmloff/qa/unit/style.cxx index 1a291a2fba84..372cf003f613 100644 --- a/xmloff/qa/unit/style.cxx +++ b/xmloff/qa/unit/style.cxx @@ -559,6 +559,43 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testBorderRestoration) SetODFDefaultVersion(nCurrentODFVersion); } +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testTransparencyBorderRestoration) +{ + // Load document. It has a shape with transparency gradient build from transparency 100% at + // offset 0, transparency 100% at offset 0.4 and transparency 10% at offset 1.0. For better + // backward compatibility such gradient is exported with a border of 40% in the transparency + // gradient. The color itself is the same for all gradient stops. + // When transparency gradient-stops are integrated in ODF strict, the test needs to be adapted. + loadFromURL(u"MCGR_TransparencyBorder_restoration.pptx"); + + // Backup original ODF default version + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion(GetODFDefaultVersion()); + + // Save to ODF_LATEST which is currently ODF 1.3 extended. Make sure transparency gradient-stop + //elements are written with offset 0 and 1, and border is written as 40%. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_LATEST); + save("impress8"); + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath = "/office:document-styles/office:styles/draw:opacity[1]"; + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[2]", "stop-opacity", "0.9"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[2]", "offset", "1"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[1]", "stop-opacity", "0"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop[1]", "offset", "0"); + assertXPath(pXmlDoc, sPath, "border", "40%"); + + // Save to ODF 1.3 strict and make sure border, start and end opacity are suitable set. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_013); + save("impress8"); + pXmlDoc = parseExport("styles.xml"); + assertXPath(pXmlDoc, sPath + "/loext:opacity-stop", 0); + assertXPath(pXmlDoc, sPath, "start", "0%"); + assertXPath(pXmlDoc, sPath, "end", "90%"); + assertXPath(pXmlDoc, sPath, "border", "40%"); + + // Set back to original ODF default version. + SetODFDefaultVersion(nCurrentODFVersion); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/TransGradientStyle.cxx b/xmloff/source/style/TransGradientStyle.cxx index d89348bbe0e8..9c268a21ff85 100644 --- a/xmloff/source/style/TransGradientStyle.cxx +++ b/xmloff/source/style/TransGradientStyle.cxx @@ -21,6 +21,7 @@ #include <com/sun/star/awt/Gradient2.hpp> +#include <basegfx/utils/bgradient.hxx> #include <comphelper/documentconstants.hxx> #include <rtl/ustrbuf.hxx> #include <rtl/ustring.hxx> @@ -169,19 +170,26 @@ void XMLTransGradientStyleExport::exportXML( const OUString& rStrName, const uno::Any& rValue ) { - awt::Gradient2 aGradient; - + // MCGR: We try to write the gradient so, that applications without multi-color gradient support + // can render it as best as possible. + // This is similar to XMLGradientStyleExport::exportXML(). For details see there. if( rStrName.isEmpty() ) return; - - if( !(rValue >>= aGradient) ) + if (!rValue.has<css::awt::Gradient2>() && !rValue.has<css::awt::Gradient>()) return; + basegfx::BGradient aGradient(rValue); + + // ToDo: aGradient.tryToConvertToAxial(); + + aGradient.tryToRecreateBorder(nullptr); + OUString aStrValue; OUStringBuffer aOut; // Style - if( !SvXMLUnitConverter::convertEnum( aOut, aGradient.Style, pXML_GradientStyle_Enum ) ) + if (!SvXMLUnitConverter::convertEnum(aOut, aGradient.GetGradientStyle(), + pXML_GradientStyle_Enum)) return; // Name @@ -197,71 +205,75 @@ void XMLTransGradientStyleExport::exportXML( rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); // Center x/y - if( aGradient.Style != awt::GradientStyle_LINEAR && - aGradient.Style != awt::GradientStyle_AXIAL ) + if (awt::GradientStyle_LINEAR != aGradient.GetGradientStyle() + && awt::GradientStyle_AXIAL != aGradient.GetGradientStyle()) { - ::sax::Converter::convertPercent(aOut, aGradient.XOffset); + ::sax::Converter::convertPercent(aOut, aGradient.GetXOffset()); aStrValue = aOut.makeStringAndClear(); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue ); - ::sax::Converter::convertPercent(aOut, aGradient.YOffset); + ::sax::Converter::convertPercent(aOut, aGradient.GetYOffset()); aStrValue = aOut.makeStringAndClear(); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue ); } - // Transparency start - Color aColor(ColorTransparency, aGradient.StartColor); - sal_Int32 aStartValue = 100 - static_cast<sal_Int32>(((aColor.GetRed() + 1) * 100) / 255); - ::sax::Converter::convertPercent( aOut, aStartValue ); + // LO uses a gray color as transparency. ODF uses opacity in range [0%,100%]. + // Default 100% opacity. + double fOpacityStartPerc = 100.0; + double fOpacityEndPerc = 100.0; + if (!aGradient.GetColorStops().empty()) + { + fOpacityStartPerc + = (1.0 - aGradient.GetColorStops().front().getStopColor().getRed()) * 100.0; + fOpacityEndPerc = (1.0 - aGradient.GetColorStops().back().getStopColor().getRed()) * 100.0; + } + + // Opacity start + ::sax::Converter::convertPercent(aOut, static_cast<sal_Int32>(std::lround(fOpacityStartPerc))); aStrValue = aOut.makeStringAndClear(); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START, aStrValue ); - // Transparency end - aColor = Color(ColorTransparency, aGradient.EndColor); - sal_Int32 aEndValue = 100 - static_cast<sal_Int32>(((aColor.GetRed() + 1) * 100) / 255); - ::sax::Converter::convertPercent( aOut, aEndValue ); + // Opacity end + ::sax::Converter::convertPercent( aOut, static_cast<sal_Int32>(std::lround(fOpacityEndPerc))); aStrValue = aOut.makeStringAndClear(); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END, aStrValue ); // Angle - if( aGradient.Style != awt::GradientStyle_RADIAL ) + if (awt::GradientStyle_RADIAL != aGradient.GetGradientStyle()) { - ::sax::Converter::convertAngle(aOut, aGradient.Angle, rExport.getSaneDefaultVersion()); + ::sax::Converter::convertAngle(aOut, aGradient.GetAngle().get(), + rExport.getSaneDefaultVersion()); aStrValue = aOut.makeStringAndClear(); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); } // Border - ::sax::Converter::convertPercent( aOut, aGradient.Border ); + ::sax::Converter::convertPercent(aOut, aGradient.GetBorder()); aStrValue = aOut.makeStringAndClear(); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); // ctor writes start tag. End-tag is written by destructor at block end. - SvXMLElementExport rElem( rExport, - XML_NAMESPACE_DRAW, XML_OPACITY, - true, false ); + 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) + if (aGradient.GetColorStops().empty()) return; + double fPreviousOffset = 0.0; - for (auto& aCandidate : aGradient.ColorStops) + for (auto& aCandidate : aGradient.GetColorStops()) { // Attribute svg:offset. Make sure offsets are increasing. - double fOffset = std::clamp<double>(aCandidate.StopOffset, 0.0, 1.0); + double fOffset = std::clamp<double>(aCandidate.getStopOffset(), 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); + double fOpacity = std::clamp<double>(1.0 - aCandidate.getStopColor().getRed(), 0.0, 1.0); rExport.AddAttribute(XML_NAMESPACE_SVG, XML_STOP_OPACITY, OUString::number(fOpacity)); // write opacity stop element commit f770cc4ec9407e0c47b40f1cb6e4b8c8fb47a9ae Author: Regina Henschel <rb.hensc...@t-online.de> AuthorDate: Wed May 31 15:16:25 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:12 2023 +0200 MCGR: Unit test for 'Use tryToRecreateBorder for...' Unit test for commit 8259a99f41367a1d8326c9157fe1902915715879. Change-Id: Iba3367fe42b5014b98cf575f53006fc09a79d6ee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152428 Tested-by: Jenkins Reviewed-by: Regina Henschel <rb.hensc...@t-online.de> diff --git a/xmloff/qa/unit/data/MCGR_Border_restoration.pptx b/xmloff/qa/unit/data/MCGR_Border_restoration.pptx new file mode 100644 index 000000000000..b43e15145f89 Binary files /dev/null and b/xmloff/qa/unit/data/MCGR_Border_restoration.pptx differ diff --git a/xmloff/qa/unit/style.cxx b/xmloff/qa/unit/style.cxx index 2d7706bf7b9e..1a291a2fba84 100644 --- a/xmloff/qa/unit/style.cxx +++ b/xmloff/qa/unit/style.cxx @@ -22,6 +22,7 @@ #include <officecfg/Office/Common.hxx> #include <rtl/character.hxx> +#include <unotools/saveopt.hxx> using namespace ::com::sun::star; @@ -520,6 +521,44 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMCGR_threeStops) CPPUNIT_ASSERT_EQUAL(0.0, aColorStop.StopColor.Blue); } +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testBorderRestoration) +{ + // Load document. It has a shape with color gradient build from color stop yellow at offset 0.5 + // and color stop red at offset 1.0. For better backward compatibility such gradient has to be + // exported to ODF with a border of 50%. + // When gradient-stops are integrated in ODF strict, the test needs to be adapted. + + loadFromURL(u"MCGR_Border_restoration.pptx"); + + // Backup original ODF default version + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion(GetODFDefaultVersion()); + + // Save to ODF_LATEST which is currently ODF 1.3 extended. Make sure gradient-stop elements have + // offsets 0 and 1, and border is written as 50%. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_LATEST); + save("impress8"); + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + OString sPath + = "/office:document-styles/office:styles/draw:gradient[@draw:name='Gradient_20_1']"; + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "color-value", "#ff0000"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[2]", "offset", "1"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "color-value", "#ffff00"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop[1]", "offset", "0"); + assertXPath(pXmlDoc, sPath, "border", "50%"); + + // Save to ODF 1.3 strict and make sure border, start-color and end-color are suitable set. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_013); + save("impress8"); + pXmlDoc = parseExport("styles.xml"); + assertXPath(pXmlDoc, sPath + "/loext:gradient-stop", 0); + assertXPath(pXmlDoc, sPath, "start-color", "#ffff00"); + assertXPath(pXmlDoc, sPath, "end-color", "#ff0000"); + assertXPath(pXmlDoc, sPath, "border", "50%"); + + // Set back to original ODF default version. + SetODFDefaultVersion(nCurrentODFVersion); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 8e3ae003634fcf3f36d7202e604be4ba134cf526 Author: Andrea Gelmini <andrea.gelm...@gelma.net> AuthorDate: Wed May 31 19:26:21 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:11 2023 +0200 Fix typo Change-Id: I9c58980de73dc2f00802f0d589d0c6fafe11d16a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152460 Tested-by: Julien Nabet <serval2...@yahoo.fr> Reviewed-by: Julien Nabet <serval2...@yahoo.fr> diff --git a/xmloff/source/style/GradientStyle.cxx b/xmloff/source/style/GradientStyle.cxx index fb1fc68fb077..7598074fc409 100644 --- a/xmloff/source/style/GradientStyle.cxx +++ b/xmloff/source/style/GradientStyle.cxx @@ -231,7 +231,7 @@ void XMLGradientStyleExport::exportXML( // MCGR: For better compatibility with LO versions before MCGR, try // to re-create a 'border' value based on the existing gradient stops. // With MCGR we do not need 'border' anymore in quite some cases since - // no Start/EndColor at 0.0 resp. 1.0 is explicitely needed. Since we + // no Start/EndColor at 0.0 resp. 1.0 is explicitly needed. Since we // (unfortunately need to) internally continue to support border // anyways it does no harm to fallback to use the border value - if // there is an equivalent representation as this helper checks for. commit 5e93d1d53631b1c188977b35c7c6d25416dcad3d Author: Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de> AuthorDate: Tue May 30 16:48:38 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:11 2023 +0200 MCGR: Use tryToRecreateBorder for better BW comp with LO For better compatibility with LO versions before MCGR, try to re-create a 'border' value based on the existing GradientSteps. With MCGR we do not need 'border' anymore in quite some cases since no Start/EndColor at 0.0 resp. 1.0 is explicitely needed. Since we (unfortunately need to) internally continue to support border anyways it does no harm to fallback to use the border value - if there is an equivalent representation as this helper checks for. For exports that do not support 'border' this will be adapted as needed (see tryToApplyBorder()) Change-Id: If98c64039ff97143d4b5c92ac2a950e70f5bb70a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152395 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/include/basegfx/utils/bgradient.hxx b/include/basegfx/utils/bgradient.hxx index ab70d05880de..b7c2cf8c9e3f 100644 --- a/include/basegfx/utils/bgradient.hxx +++ b/include/basegfx/utils/bgradient.hxx @@ -335,7 +335,7 @@ public: css::awt::Gradient2 getAsGradient2() const; /// Tooling to handle border correction/integration and StartStopIntensity - void tryToRecreateBorder(basegfx::BColorStops* pAssociatedTransparencyStops); + void tryToRecreateBorder(basegfx::BColorStops* pAssociatedTransparencyStops = nullptr); void tryToApplyBorder(); void tryToApplyStartEndIntensity(); }; diff --git a/xmloff/source/style/GradientStyle.cxx b/xmloff/source/style/GradientStyle.cxx index fcc371c89ffb..fb1fc68fb077 100644 --- a/xmloff/source/style/GradientStyle.cxx +++ b/xmloff/source/style/GradientStyle.cxx @@ -34,6 +34,7 @@ #include <xmloff/xmltkmap.hxx> #include <xmloff/xmltoken.hxx> #include <xmloff/xmluconv.hxx> +#include <basegfx/utils/bgradient.hxx> using namespace ::com::sun::star; using namespace ::xmloff::token; @@ -219,19 +220,30 @@ void XMLGradientStyleExport::exportXML( const OUString& rStrName, const uno::Any& rValue ) { - awt::Gradient2 aGradient; - if( rStrName.isEmpty() ) return; - if( !(rValue >>= aGradient) ) + if (!rValue.has<css::awt::Gradient2>() && !rValue.has<css::awt::Gradient>()) return; + basegfx::BGradient aGradient(rValue); + + // MCGR: For better compatibility with LO versions before MCGR, try + // to re-create a 'border' value based on the existing gradient stops. + // With MCGR we do not need 'border' anymore in quite some cases since + // no Start/EndColor at 0.0 resp. 1.0 is explicitely needed. Since we + // (unfortunately need to) internally continue to support border + // anyways it does no harm to fallback to use the border value - if + // there is an equivalent representation as this helper checks for. + // For exports that do not support 'border' this will be adapted as + // needed (see tryToApplyBorder()). + aGradient.tryToRecreateBorder(nullptr); + OUString aStrValue; OUStringBuffer aOut; // Style - if( !SvXMLUnitConverter::convertEnum( aOut, aGradient.Style, pXML_GradientStyle_Enum ) ) + if( !SvXMLUnitConverter::convertEnum( aOut, aGradient.GetGradientStyle(), pXML_GradientStyle_Enum ) ) return; // Name @@ -247,47 +259,57 @@ void XMLGradientStyleExport::exportXML( m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); // Center x/y - if( aGradient.Style != awt::GradientStyle_LINEAR && - aGradient.Style != awt::GradientStyle_AXIAL ) + if( aGradient.GetGradientStyle() != awt::GradientStyle_LINEAR && + aGradient.GetGradientStyle() != awt::GradientStyle_AXIAL ) { - ::sax::Converter::convertPercent(aOut, aGradient.XOffset); + ::sax::Converter::convertPercent(aOut, aGradient.GetXOffset()); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue ); - ::sax::Converter::convertPercent(aOut, aGradient.YOffset); + ::sax::Converter::convertPercent(aOut, aGradient.GetYOffset()); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue ); } + // prep Start/EndColor, default black + basegfx::BColor aStartColor; + basegfx::BColor aEndColor; + + if (!aGradient.GetColorStops().empty()) + { + aStartColor = aGradient.GetColorStops().front().getStopColor(); + aEndColor = aGradient.GetColorStops().back().getStopColor(); + } + // Color start - ::sax::Converter::convertColor(aOut, aGradient.StartColor); + ::sax::Converter::convertColor(aOut, Color(aStartColor)); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_COLOR, aStrValue ); // Color end - ::sax::Converter::convertColor(aOut, aGradient.EndColor); + ::sax::Converter::convertColor(aOut, Color(aEndColor)); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_COLOR, aStrValue ); // Intensity start - ::sax::Converter::convertPercent(aOut, aGradient.StartIntensity); + ::sax::Converter::convertPercent(aOut, aGradient.GetStartIntens()); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_INTENSITY, aStrValue ); // Intensity end - ::sax::Converter::convertPercent(aOut, aGradient.EndIntensity); + ::sax::Converter::convertPercent(aOut, aGradient.GetEndIntens()); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_INTENSITY, aStrValue ); // Angle - if( aGradient.Style != awt::GradientStyle_RADIAL ) + if( aGradient.GetGradientStyle() != awt::GradientStyle_RADIAL ) { - ::sax::Converter::convertAngle(aOut, aGradient.Angle, m_rExport.getSaneDefaultVersion()); + ::sax::Converter::convertAngle(aOut, static_cast<sal_Int16>(aGradient.GetAngle()), m_rExport.getSaneDefaultVersion()); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); } // Border - ::sax::Converter::convertPercent( aOut, aGradient.Border ); + ::sax::Converter::convertPercent( aOut, aGradient.GetBorder() ); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); @@ -299,15 +321,15 @@ void XMLGradientStyleExport::exportXML( // Do not export in standard ODF 1.3 or older. if ((m_rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) return; - sal_Int32 nCount = aGradient.ColorStops.getLength(); - if (nCount == 0) + + if (aGradient.GetColorStops().empty()) return; double fPreviousOffset = 0.0; - for (auto& aCandidate : aGradient.ColorStops) + for (const auto& aCandidate : aGradient.GetColorStops()) { // Attribute svg:offset. Make sure offsets are increasing. - double fOffset = std::clamp<double>(aCandidate.StopOffset, 0.0, 1.0); + double fOffset = std::clamp<double>(aCandidate.getStopOffset(), 0.0, 1.0); if (fOffset < fPreviousOffset) fOffset = fPreviousOffset; m_rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset)); @@ -317,10 +339,10 @@ void XMLGradientStyleExport::exportXML( m_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)); + const basegfx::BColor aDecimalColor(aCandidate.getStopColor()); + ::Color aToolsColor(std::clamp<sal_uInt8>(std::round(aDecimalColor.getRed() * 255.0), 0, 255), + std::clamp<sal_uInt8>(std::round(aDecimalColor.getGreen() * 255.0), 0, 255), + std::clamp<sal_uInt8>(std::round(aDecimalColor.getBlue() * 255.0), 0, 255)); m_rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_COLOR_VALUE, rtl::OUStringChar('#') + aToolsColor.AsRGBHexString()); commit 5b6ae81ec086e4b120bc7b66938f17a485a7d8aa Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon May 22 08:27:57 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:11 2023 +0200 sw: prefix members of XMLGradientStyleExport, XMLGradientStyleImport, ... ... XMLHatchStyleExport and XMLHatchStyleImport See tdf#94879 for motivation. Change-Id: I2dd4c97c6e234447190e46bd6f6a6354e16911bf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152077 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/include/xmloff/GradientStyle.hxx b/include/xmloff/GradientStyle.hxx index 04ad2832d997..58975644fb3d 100644 --- a/include/xmloff/GradientStyle.hxx +++ b/include/xmloff/GradientStyle.hxx @@ -37,7 +37,7 @@ namespace com::sun::star { class XMLOFF_DLLPUBLIC XMLGradientStyleImport { - SvXMLImport& rImport; + SvXMLImport& m_rImport; public: XMLGradientStyleImport( SvXMLImport& rImport ); @@ -60,7 +60,7 @@ public: class XMLOFF_DLLPUBLIC XMLGradientStyleExport { - SvXMLExport& rExport; + SvXMLExport& m_rExport; public: XMLGradientStyleExport( SvXMLExport& rExport ); diff --git a/include/xmloff/HatchStyle.hxx b/include/xmloff/HatchStyle.hxx index 9ded654e53e2..73c07e643a2c 100644 --- a/include/xmloff/HatchStyle.hxx +++ b/include/xmloff/HatchStyle.hxx @@ -35,7 +35,7 @@ namespace com::sun::star { class XMLOFF_DLLPUBLIC XMLHatchStyleImport { - SvXMLImport& rImport; + SvXMLImport& m_rImport; public: XMLHatchStyleImport( SvXMLImport& rImport ); @@ -48,7 +48,7 @@ public: class XMLOFF_DLLPUBLIC XMLHatchStyleExport { - SvXMLExport& rExport; + SvXMLExport& m_rExport; public: XMLHatchStyleExport( SvXMLExport& rExport ); diff --git a/xmloff/source/style/GradientStyle.cxx b/xmloff/source/style/GradientStyle.cxx index 3ab6c422b2c8..fcc371c89ffb 100644 --- a/xmloff/source/style/GradientStyle.cxx +++ b/xmloff/source/style/GradientStyle.cxx @@ -52,7 +52,7 @@ SvXMLEnumMapEntry<awt::GradientStyle> const pXML_GradientStyle_Enum[] = // Import XMLGradientStyleImport::XMLGradientStyleImport( SvXMLImport& rImp ) - : rImport(rImp) + : m_rImport(rImp) { } @@ -114,14 +114,14 @@ void XMLGradientStyleImport::importXML( break; case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE): { - auto const cmp12(rImport.GetODFVersion().compareTo(ODFVER_012_TEXT)); + auto const cmp12(m_rImport.GetODFVersion().compareTo(ODFVER_012_TEXT)); bool const bSuccess = ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(), // tdf#89475 try to detect borked OOo angles (cmp12 < 0) || (cmp12 == 0 - && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) + && (m_rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) // also for AOO 4.x, assume there won't ever be a 4.2 - || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + || m_rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle"); } break; @@ -139,7 +139,7 @@ void XMLGradientStyleImport::importXML( if( !aDisplayName.isEmpty() ) { - rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName, + m_rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName, aDisplayName ); rStrName = aDisplayName; } @@ -211,7 +211,7 @@ XMLGradientStopContext::~XMLGradientStopContext() XMLGradientStyleExport::XMLGradientStyleExport( SvXMLExport& rExp ) - : rExport(rExp) + : m_rExport(rExp) { } @@ -236,15 +236,15 @@ void XMLGradientStyleExport::exportXML( // Name bool bEncoded = false; - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, - rExport.EncodeStyleName( rStrName, + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + m_rExport.EncodeStyleName( rStrName, &bEncoded ) ); if( bEncoded ) - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, rStrName ); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); // Center x/y if( aGradient.Style != awt::GradientStyle_LINEAR && @@ -252,52 +252,52 @@ void XMLGradientStyleExport::exportXML( { ::sax::Converter::convertPercent(aOut, aGradient.XOffset); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue ); ::sax::Converter::convertPercent(aOut, aGradient.YOffset); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue ); } // Color start ::sax::Converter::convertColor(aOut, aGradient.StartColor); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_COLOR, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_COLOR, aStrValue ); // Color end ::sax::Converter::convertColor(aOut, aGradient.EndColor); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_COLOR, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_COLOR, aStrValue ); // Intensity start ::sax::Converter::convertPercent(aOut, aGradient.StartIntensity); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_INTENSITY, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_INTENSITY, aStrValue ); // Intensity end ::sax::Converter::convertPercent(aOut, aGradient.EndIntensity); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_INTENSITY, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_INTENSITY, aStrValue ); // Angle if( aGradient.Style != awt::GradientStyle_RADIAL ) { - ::sax::Converter::convertAngle(aOut, aGradient.Angle, rExport.getSaneDefaultVersion()); + ::sax::Converter::convertAngle(aOut, aGradient.Angle, m_rExport.getSaneDefaultVersion()); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); } // Border ::sax::Converter::convertPercent( aOut, aGradient.Border ); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); // ctor writes start tag. End-tag is written by destructor at block end. - SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_GRADIENT, + SvXMLElementExport aElem( m_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) + if ((m_rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) return; sal_Int32 nCount = aGradient.ColorStops.getLength(); if (nCount == 0) @@ -310,22 +310,22 @@ void XMLGradientStyleExport::exportXML( 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)); + m_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"); + m_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, + m_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); + SvXMLElementExport aStopElement(m_rExport, XML_NAMESPACE_LO_EXT, XML_GRADIENT_STOP, true, true); } } diff --git a/xmloff/source/style/HatchStyle.cxx b/xmloff/source/style/HatchStyle.cxx index a70ee506ed3b..2a0bc2259757 100644 --- a/xmloff/source/style/HatchStyle.cxx +++ b/xmloff/source/style/HatchStyle.cxx @@ -50,7 +50,7 @@ SvXMLEnumMapEntry<drawing::HatchStyle> const pXML_HatchStyle_Enum[] = // Import XMLHatchStyleImport::XMLHatchStyleImport( SvXMLImport& rImp ) - : rImport(rImp) + : m_rImport(rImp) { } @@ -67,7 +67,7 @@ void XMLHatchStyleImport::importXML( aHatch.Distance = 0; aHatch.Angle = 0; - SvXMLUnitConverter& rUnitConverter = rImport.GetMM100UnitConverter(); + SvXMLUnitConverter& rUnitConverter = m_rImport.GetMM100UnitConverter(); for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) { @@ -110,7 +110,7 @@ void XMLHatchStyleImport::importXML( if( !aDisplayName.isEmpty() ) { - rImport.AddStyleDisplayName( XmlStyleFamily::SD_HATCH_ID, rStrName, + m_rImport.AddStyleDisplayName( XmlStyleFamily::SD_HATCH_ID, rStrName, aDisplayName ); rStrName = aDisplayName; } @@ -119,7 +119,7 @@ void XMLHatchStyleImport::importXML( // Export XMLHatchStyleExport::XMLHatchStyleExport( SvXMLExport& rExp ) - : rExport(rExp) + : m_rExport(rExp) { } @@ -139,7 +139,7 @@ void XMLHatchStyleExport::exportXML( OUStringBuffer aOut; SvXMLUnitConverter& rUnitConverter = - rExport.GetMM100UnitConverter(); + m_rExport.GetMM100UnitConverter(); // Style if( !SvXMLUnitConverter::convertEnum( aOut, aHatch.Style, pXML_HatchStyle_Enum ) ) @@ -147,31 +147,31 @@ void XMLHatchStyleExport::exportXML( // Name bool bEncoded = false; - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, - rExport.EncodeStyleName( rStrName, + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + m_rExport.EncodeStyleName( rStrName, &bEncoded ) ); if( bEncoded ) - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, rStrName ); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); // Color ::sax::Converter::convertColor(aOut, aHatch.Color); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_COLOR, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_COLOR, aStrValue ); // Distance rUnitConverter.convertMeasureToXML( aOut, aHatch.Distance ); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISTANCE, aStrValue ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISTANCE, aStrValue ); // Angle - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ROTATION, OUString::number(aHatch.Angle) ); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ROTATION, OUString::number(aHatch.Angle) ); // Do Write - SvXMLElementExport rElem( rExport, XML_NAMESPACE_DRAW, XML_HATCH, + SvXMLElementExport rElem( m_rExport, XML_NAMESPACE_DRAW, XML_HATCH, true, false ); } commit 4dd9fbf0b27a82d002237cf8fe25a843926500a8 Author: Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de> AuthorDate: Tue May 30 15:16:08 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:11 2023 +0200 MCGR: tdf#155437 handling of TransparencePrimitive2D for metafiles In VclMetafileProcessor2D we need to take care of changed circumstances for gradients with the MCGR adaptions. The method processTransparencePrimitive2D tries to detect the special case that the trapsparency part of the handled TransparencePrimitive2D is a single TransparencyGradient. If detected, this is handed directly to vcl using a MetaFloatTransparentAction which contains a class 'Gradient', but the limited form from vcl (see include/vcl/gradient.hxx). This class can only in very limited scenarios directly handle/hold a gradient from the model (even before MCGR). For that case there is the helper method 'cannotBeHandledByVCL' that is already used to decide if limited direct rendering using vcl can be used. This has also be used here. Also reworked the conversion to Bitmap as needed, the existing versions created slight errors. For more details see additional comments in the code. Change-Id: If9af8b1423df5354eaf9ba8ca6243a1b3ad1b965 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152392 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index 2c353a64c5f6..2d78ef686264 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -64,6 +64,8 @@ #include <drawinglayer/primitive2d/epsprimitive2d.hxx> #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx> #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx> // for Title/Description metadata +#include <drawinglayer/converters.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <com/sun/star/awt/XControl.hpp> #include <com/sun/star/i18n/BreakIterator.hpp> @@ -2276,28 +2278,59 @@ void VclMetafileProcessor2D::processTransparencePrimitive2D( // FillGradientPrimitive2D and reconstruct the gradient. // If that detection goes wrong, I have to create a transparence-blended bitmap. Eventually // do that in stripes, else RenderTransparencePrimitive2D may just be used - const primitive2d::Primitive2DContainer& rContent = rTransparenceCandidate.getChildren(); - const primitive2d::Primitive2DContainer& rTransparence - = rTransparenceCandidate.getTransparence(); + const primitive2d::Primitive2DContainer& rContent(rTransparenceCandidate.getChildren()); + const primitive2d::Primitive2DContainer& rTransparence( + rTransparenceCandidate.getTransparence()); if (rContent.empty() || rTransparence.empty()) return; // try to identify a single FillGradientPrimitive2D in the - // transparence part of the primitive - const primitive2d::FillGradientPrimitive2D* pFiGradient = nullptr; + // transparence part of the primitive. The hope is to handle + // the more specific case in a better way than the general + // TransparencePrimitive2D which has strongly seperated + // definitions for transparency and content, both completely + // free definable by primitives + const primitive2d::FillGradientPrimitive2D* pFiGradient(nullptr); static bool bForceToBigTransparentVDev(false); // loplugin:constvars:ignore + // check for single FillGradientPrimitive2D if (!bForceToBigTransparentVDev && 1 == rTransparence.size()) { - const primitive2d::Primitive2DReference xReference(rTransparence[0]); - pFiGradient = dynamic_cast<const primitive2d::FillGradientPrimitive2D*>(xReference.get()); + pFiGradient + = dynamic_cast<const primitive2d::FillGradientPrimitive2D*>(rTransparence[0].get()); + + // check also for correct ID to exclude derived implementations + if (pFiGradient + && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D != pFiGradient->getPrimitive2DID()) + pFiGradient = nullptr; } - // Check also for correct ID to exclude derived implementations - if (pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID()) + // MCGR: tdf#155437 If we have identified a transparency gradient, + // check if VCL is able to handle it at all + if (nullptr != pFiGradient && pFiGradient->getFillGradient().cannotBeHandledByVCL()) { - // various content, create content-metafile + // If not, reset the pointer and do not make use of this special case. + // Adding a gradient in incomplete state that canot be handled by vcl + // makes no sense and will knowingly lead to errors, especially with + // MCGR extended possibilities. I checked what happens with the + // MetaFloatTransparentAction added by OutputDevice::DrawTransparent, but + // in most cases it gets converted to bitmap or even ignored, see e.g. + // - vcl/source/gdi/pdfwriter_impl2.cxx for PDF export + // - vcl/source/filter/wmf/wmfwr.cxx -> does ignore TransparenceGradient completely + // - vcl/source/filter/wmf/emfwr.cxx -> same + // - vcl/source/filter/eps/eps.cxx -> same + // NOTE: Theoretically it would be possible to make the new extended Gradient data + // available in metafiles, with the known limitiations (not backward comp, all + // places using it would need adaption, ...), but combined with knowing that nearly + // all usages ignore or render it locally anyways makes that a non-option. + pFiGradient = nullptr; + } + + if (nullptr != pFiGradient) + { + // this combination of Gradient can be expressed/handled by + // vcl/metafile, so add it directly. various content, create content-metafile GDIMetaFile aContentMetafile; const tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); @@ -2306,101 +2339,71 @@ void VclMetafileProcessor2D::processTransparencePrimitive2D( impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true); - // render it to VCL + // render it to VCL (creates MetaFloatTransparentAction) mpOutputDevice->DrawTransparent(aContentMetafile, aPrimitiveRectangle.TopLeft(), aPrimitiveRectangle.GetSize(), aVCLGradient); + return; } - else - { - // sub-transparence group. Draw to VDev first. - // this may get refined to tiling when resolution is too big here - - // need to avoid switching off MapMode stuff here; maybe need another - // tooling class, cannot just do the same as with the pixel renderer. - // Need to experiment... - - // Okay, basic implementation finished and tested. The DPI stuff was hard - // and not easy to find out that it's needed. - // Since this will not yet happen normally (as long as no one constructs - // transparence primitives with non-trivial transparence content) i will for now not - // refine to tiling here. - - basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D())); - aViewRange.transform(maCurrentTransformation); - const tools::Rectangle aRectLogic(static_cast<sal_Int32>(floor(aViewRange.getMinX())), - static_cast<sal_Int32>(floor(aViewRange.getMinY())), - static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), - static_cast<sal_Int32>(ceil(aViewRange.getMaxY()))); - const tools::Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic)); - Size aSizePixel(aRectPixel.GetSize()); - ScopedVclPtrInstance<VirtualDevice> aBufferDevice; - const sal_uInt32 nMaxSquarePixels(500000); - const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight()); - double fReduceFactor(1.0); - - if (nViewVisibleArea > nMaxSquarePixels) - { - // reduce render size - fReduceFactor = sqrt(double(nMaxSquarePixels) / static_cast<double>(nViewVisibleArea)); - aSizePixel = Size( - basegfx::fround(static_cast<double>(aSizePixel.getWidth()) * fReduceFactor), - basegfx::fround(static_cast<double>(aSizePixel.getHeight()) * fReduceFactor)); - } - - if (aBufferDevice->SetOutputSizePixel(aSizePixel)) - { - // create and set MapModes for target devices - MapMode aNewMapMode(mpOutputDevice->GetMapMode()); - aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top())); - aBufferDevice->SetMapMode(aNewMapMode); - - // prepare view transformation for target renderers - // ATTENTION! Need to apply another scaling because of the potential DPI differences - // between Printer and VDev (mpOutputDevice and aBufferDevice here). - // To get the DPI, LogicToPixel from (1,1) from MapUnit::MapInch needs to be used. - basegfx::B2DHomMatrix aViewTransform(aBufferDevice->GetViewTransformation()); - const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch))); - const Size aDPINew(aBufferDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch))); - const double fDPIXChange(static_cast<double>(aDPIOld.getWidth()) - / static_cast<double>(aDPINew.getWidth())); - const double fDPIYChange(static_cast<double>(aDPIOld.getHeight()) - / static_cast<double>(aDPINew.getHeight())); - - if (!basegfx::fTools::equal(fDPIXChange, 1.0) - || !basegfx::fTools::equal(fDPIYChange, 1.0)) - { - aViewTransform.scale(fDPIXChange, fDPIYChange); - } - // also take scaling from Size reduction into account - if (!basegfx::fTools::equal(fReduceFactor, 1.0)) - { - aViewTransform.scale(fReduceFactor, fReduceFactor); - } - - // create view information and pixel renderer. Reuse known ViewInformation - // except new transformation and range - geometry::ViewInformation2D aViewInfo(getViewInformation2D()); - aViewInfo.setViewTransformation(aViewTransform); - aViewInfo.setViewport(aViewRange); - - VclPixelProcessor2D aBufferProcessor(aViewInfo, *aBufferDevice); - - // draw content using pixel renderer - const Point aEmptyPoint; - aBufferProcessor.process(rContent); - const Bitmap aBmContent(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel)); - - // draw transparence using pixel renderer - aBufferDevice->Erase(); - aBufferProcessor.process(rTransparence); - const AlphaMask aBmAlpha(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel)); - - // paint - mpOutputDevice->DrawBitmapEx(aRectLogic.TopLeft(), aRectLogic.GetSize(), - BitmapEx(aBmContent, aBmAlpha)); - } - } + // Here we need to create a correct replacement visualization for the + // TransparencePrimitive2D for the target metafile. + // I replaced the n'th iteration to convert-to-bitmap which was + // used here by using the existing tooling. The orig here was also producing + // transparency errors with test-file from tdf#155437 on the right part of the + // image. + // Just rely on existing tooling doing the right thing in one place, so also + // corrections/optimizations can be in one single place + + // Start by getting logic range of content, transform object-to-world, then world-to-view + // to get to discrete values ('pixels'). Matrix multiplication is right-to-left (and not + // commutative) + basegfx::B2DRange aLogicRange(rTransparenceCandidate.getB2DRange(getViewInformation2D())); + aLogicRange.transform(mpOutputDevice->GetViewTransformation() * maCurrentTransformation); + + // expand in discrete coordinates to next-bigger 'pixel' boundaries and remember + // created discrete range + aLogicRange.expand( + basegfx::B2DPoint(floor(aLogicRange.getMinX()), floor(aLogicRange.getMinY()))); + aLogicRange.expand(basegfx::B2DPoint(ceil(aLogicRange.getMaxX()), ceil(aLogicRange.getMaxY()))); + const basegfx::B2DRange aDiscreteRange(aLogicRange); + + // transform back from discrete to world coordinates: this creates the + // pixel-boundaries extended logic range we need to cover all content + // reliably + aLogicRange.transform(mpOutputDevice->GetInverseViewTransformation()); + + // create transform embedding for renderer. Goal is to translate what we + // want to paint to top/left 0/0 and the calculated discrete size + basegfx::B2DHomMatrix aEmbedding(basegfx::utils::createTranslateB2DHomMatrix( + -aLogicRange.getMinX(), -aLogicRange.getMinY())); + const double fLogicWidth( + basegfx::fTools::equalZero(aLogicRange.getWidth()) ? 1.0 : aLogicRange.getWidth()); + const double fLogicHeight( + basegfx::fTools::equalZero(aLogicRange.getHeight()) ? 1.0 : aLogicRange.getHeight()); + aEmbedding.scale(aDiscreteRange.getWidth() / fLogicWidth, + aDiscreteRange.getHeight() / fLogicHeight); + + // use the whole TransparencePrimitive2D as input (no need to create a new + // one with the sub-contents, these are ref-counted) and add to embedding + // primitive2d::TransparencePrimitive2D& rTrCand(); + primitive2d::Primitive2DContainer xEmbedSeq{ &const_cast<primitive2d::TransparencePrimitive2D&>( + rTransparenceCandidate) }; + xEmbedSeq = primitive2d::Primitive2DContainer{ new primitive2d::TransformPrimitive2D( + aEmbedding, std::move(xEmbedSeq)) }; + + // use empty ViewInformation & a useful MaximumQuadraticPixels + // limitation to paint the content + const auto aViewInformation2D(geometry::createViewInformation2D({})); + const sal_uInt32 nMaximumQuadraticPixels(500000); + const BitmapEx aBitmapEx(convertToBitmapEx( + std::move(xEmbedSeq), aViewInformation2D, basegfx::fround(aDiscreteRange.getWidth()), + basegfx::fround(aDiscreteRange.getHeight()), nMaximumQuadraticPixels)); + + // add to target metafile (will create MetaFloatTransparentAction) + mpOutputDevice->DrawBitmapEx( + Point(basegfx::fround(aLogicRange.getMinX()), basegfx::fround(aLogicRange.getMinY())), + Size(basegfx::fround(aLogicRange.getWidth()), basegfx::fround(aLogicRange.getHeight())), + aBitmapEx); } void VclMetafileProcessor2D::processStructureTagPrimitive2D( commit 10f8cdb5ba93953d9efcc3959c8b886f993ddbbb Author: Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de> AuthorDate: Wed May 24 12:31:48 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:11 2023 +0200 MCGR: Border restoration support Due to tdf#155362 I added code to be able in case we would need it to convert a BGradient using added tooling from having offsets in the GradientSteps and no border to adapted GradientSteps and border. This is preferrable due to our GradientStyle_RECT (and GradientStyle_ELLIPTICAL too) use that 'non- linear' paint aka move-two-pixels-inside, someone else called it 'frame-paint'. This does not bode well with the border being applied 'linear' at the same time (argh). Thus - while in principle all is correct when re-importing a GradientStyle_RECT with a border after export to pptx, it looks slightly better ('correcter') wen doing so. That is because when being able to and restoring a border at least that border part *is* applied linearly. I took the chance to further apply tooling, move it to classes involved and instead of awt::Gradient2 use more basegfx::BGradient since it can and does host tooling. This is also a preparation to be able to adapt (restore) border in case of turn- around in ODF where the importing instance is before MCGR existance and has to handle Start/EndColor. Needed to take more care with using BGradient instead of awt::Gradient2 for initialization, also better dividing/organization of tooling, already preparation to use for other purposes. Change-Id: I2d3a4240a5ac6fff9211b46642ee80366dc09e3d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152194 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/basegfx/source/tools/bgradient.cxx b/basegfx/source/tools/bgradient.cxx index 1499b0c682fe..375b9685edc5 100644 --- a/basegfx/source/tools/bgradient.cxx +++ b/basegfx/source/tools/bgradient.cxx @@ -563,6 +563,100 @@ void BColorStops::reverseColorStops() candidate = BColorStop(1.0 - candidate.getStopOffset(), candidate.getStopColor()); } +// createSpaceAtStart creates fOffset space at start by +// translating/scaling all entries to the right +void BColorStops::createSpaceAtStart(double fOffset) +{ + // nothing to do if empty + if (empty()) + return; + + // correct offset to [0.0 .. 1.0] + fOffset = std::max(std::min(1.0, fOffset), 0.0); + + // nothing to do if 0.0 == offset + if (basegfx::fTools::equalZero(fOffset)) + return; + + BColorStops aNewStops; + + for (const auto& candidate : *this) + { + aNewStops.emplace_back(fOffset + (candidate.getStopOffset() * (1.0 - fOffset)), + candidate.getStopColor()); + } + + *this = aNewStops; +} + +// removeSpaceAtStart removes fOffset space from start by +// translating/scaling entries more or equal to fOffset +// to the left. Entries less than fOffset will be removed +void BColorStops::removeSpaceAtStart(double fOffset) +{ + // nothing to do if empty + if (empty()) + return; + + // correct factor to [0.0 .. 1.0] + fOffset = std::max(std::min(1.0, fOffset), 0.0); + + // nothing to do if fOffset == 0.0 + if (basegfx::fTools::equalZero(fOffset)) + return; + + BColorStops aNewStops; + const double fMul(basegfx::fTools::equal(fOffset, 1.0) ? 1.0 : 1.0 / (1.0 - fOffset)); + + for (const auto& candidate : *this) + { + if (basegfx::fTools::moreOrEqual(candidate.getStopOffset(), fOffset)) + { + aNewStops.emplace_back((candidate.getStopOffset() - fOffset) * fMul, + candidate.getStopColor()); + } + } + + *this = aNewStops; +} + +// try to detect if an empty/no-color-change area exists +// at the start and return offset to it. Returns 0.0 if not. +double BColorStops::detectPossibleOffsetAtStart() const +{ + BColor aSingleColor; + const bool bSingleColor(isSingleColor(aSingleColor)); + + // no useful offset for single color + if (bSingleColor) + return 0.0; + + // here we know that we have at least two colors, so we have a + // color change. Find colors left and right of that first color change + BColorStops::const_iterator aColorR(begin()); + BColorStops::const_iterator aColorL(aColorR++); + + // aColorR would 1st get equal to end(), so no need to also check aColorL + // for end(). Loop as long as same color. Since we *have* a color change + // not even aColorR can get equal to end() before color inequality, but + // keep for safety + while (aColorR != end() && aColorL->getStopColor() == aColorR->getStopColor()) + { + aColorL++; + aColorR++; + } + + // also for safety: access values at aColorL below *only* + // if not equal to end(), but can theoretically not happen + if (aColorL == end()) + { + return 0.0; + } + + // return offset (maybe 0.0 what is OK) + return aColorL->getStopOffset(); +} + std::string BGradient::GradientStyleToString(css::awt::GradientStyle eStyle) { switch (eStyle) @@ -757,7 +851,24 @@ css::awt::Gradient2 BGradient::getAsGradient2() const aRetval.StepCount = GetSteps(); // for compatibility, still set StartColor/EndColor - // const basegfx::BColorStops& rColorStops(GetColorStops()); + // NOTE: All code after adapting to multi color gradients works + // using the ColorSteps, so in principle Start/EndColor might + // be either + // (a) ignored consequently everywhere or + // (b) be set/added consequently everywhere + // since this is - in principle - redundant data. + // Be aware that e.g. cases like DrawingML::EqualGradients + // and others would have to be identified and adapted (!) + // Since awt::Gradient2 is UNO API data there might + // be cases where just awt::Gradient is transferred, so (b) + // is far better backwards compatible and thus more safe, so + // all changes will make use of additionally using/setting + // these additionally, but will only make use of the given + // ColorSteps if these are not empty, assuming that these + // already contain Start/EndColor. + // In principle that redundancy and that it is conflict-free + // could even be checked and asserted, but consequently using + // (b) methodically should be safe. aRetval.StartColor = static_cast<sal_Int32>(ColorToBColorConverter(aColorStops.front().getStopColor())); aRetval.EndColor @@ -765,10 +876,101 @@ css::awt::Gradient2 BGradient::getAsGradient2() const // fill ColorStops to extended Gradient2 aRetval.ColorStops = aColorStops.getAsColorStopSequence(); - // fillColorStopSequenceFromColorStops(rGradient2.ColorStops, rColorStops); return aRetval; } + +void BGradient::tryToRecreateBorder(basegfx::BColorStops* pAssociatedTransparencyStops) +{ + // border already set, do not try to recreate + if (0 != GetBorder()) + return; + + BColor aSingleColor; + const bool bSingleColor(GetColorStops().isSingleColor(aSingleColor)); + + // no need to recreate with single color + if (bSingleColor) + return; + + const bool bIsAxial(css::awt::GradientStyle_AXIAL == GetGradientStyle()); + + if (bIsAxial) + { + // for axial due to reverse used gradient work reversed + aColorStops.reverseColorStops(); + if (nullptr != pAssociatedTransparencyStops) + pAssociatedTransparencyStops->reverseColorStops(); + } + + // check if we have space at start of range [0.0 .. 1.0] that + // may be interpreted as 'border' -> same color. That may involve + // different scenarios, e.g. 1st index > 0.0, but also a non-zero + // number of same color entries, or a combination of both + const double fOffset(aColorStops.detectPossibleOffsetAtStart()); + + if (!basegfx::fTools::equalZero(fOffset)) + { + // we have a border area, indeed re-create + aColorStops.removeSpaceAtStart(fOffset); + if (nullptr != pAssociatedTransparencyStops) + pAssociatedTransparencyStops->removeSpaceAtStart(fOffset); + + // ...and create border value + SetBorder(static_cast<sal_uInt16>(fOffset * 100.0)); + } + + if (bIsAxial) + { + // take back reverse + aColorStops.reverseColorStops(); + if (nullptr != pAssociatedTransparencyStops) + pAssociatedTransparencyStops->reverseColorStops(); + } +} + +void BGradient::tryToApplyBorder() +{ + // no border to apply, done + if (0 == GetBorder()) + return; + + // NOTE: no new start node is added. The new ColorStop + // mechanism does not need entries at 0.0 and 1.0. + // In case this is needed, do that in the caller + const double fOffset(GetBorder() * 0.01); + + if (css::awt::GradientStyle_AXIAL == GetGradientStyle()) + { + // for axial due to reverse used gradient work reversed + aColorStops.reverseColorStops(); + aColorStops.createSpaceAtStart(fOffset); + aColorStops.reverseColorStops(); + } + else + { + // apply border to GradientSteps + aColorStops.createSpaceAtStart(fOffset); + } + + // set changed values + SetBorder(0); +} + +void BGradient::tryToApplyStartEndIntensity() +{ + // already on default, nothing to apply + if (100 == GetStartIntens() && 100 == GetEndIntens()) + return; + + // apply 'old' blend stuff, blend against black + aColorStops.blendToIntensity(GetStartIntens() * 0.01, GetEndIntens() * 0.01, + BColor()); // COL_BLACK + + // set values to default + SetStartIntens(100); + SetEndIntens(100); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx index 2cc455aa0342..9ccfbd71d605 100644 --- a/basegfx/source/tools/gradienttools.cxx +++ b/basegfx/source/tools/gradienttools.cxx @@ -265,28 +265,15 @@ namespace basegfx namespace utils { - /* Tooling method to extract data from given awt::Gradient2 - to ColorStops, doing some corrections, partitally based - on given SingleColor. - This will do quite some preparations for the gradient - as follows: - - It will check for single color (resetting rSingleColor when - this is the case) and return with empty ColorStops - - It will blend ColorStops to Intensity if StartIntensity/ - EndIntensity != 100 is set in awt::Gradient2, so applying - that value(s) to the gadient directly - - It will adapt to Border if Border != 0 is set at the - given awt::Gradient2, so applying that value to the gadient - directly - */ + /* Tooling method to extract data from given BGradient + to ColorStops, doing some corrections, partially based + on given SingleColor */ void prepareColorStops( const basegfx::BGradient& rGradient, BColorStops& rColorStops, BColor& rSingleColor) { - rColorStops = rGradient.GetColorStops(); - - if (rColorStops.isSingleColor(rSingleColor)) + if (rGradient.GetColorStops().isSingleColor(rSingleColor)) { // when single color, preserve value in rSingleColor // and clear the ColorStops, done. @@ -294,73 +281,45 @@ namespace basegfx return; } - if (100 != rGradient.GetStartIntens() || 100 != rGradient.GetEndIntens()) + const bool bAdaptStartEndIntensity(100 != rGradient.GetStartIntens() || 100 != rGradient.GetEndIntens()); + const bool bAdaptBorder(0 != rGradient.GetBorder()); + + if (!bAdaptStartEndIntensity && !bAdaptBorder) { - // apply 'old' blend stuff, blend against black - rColorStops.blendToIntensity( - rGradient.GetStartIntens() * 0.01, - rGradient.GetEndIntens() * 0.01, - basegfx::BColor()); // COL_BLACK - - // can lead to single color (e.g. both zero, so all black), - // so check again - if (rColorStops.isSingleColor(rSingleColor)) + // copy unchanged ColorStops & done + rColorStops = rGradient.GetColorStops(); + return; + } + + // prepare a copy to work on + basegfx::BGradient aWorkCopy(rGradient); + + if (bAdaptStartEndIntensity) + { + aWorkCopy.tryToApplyStartEndIntensity(); + + // this can again lead to single color (e.g. both zero, so + // all black), so check again for it + if (aWorkCopy.GetColorStops().isSingleColor(rSingleColor)) { rColorStops.clear(); return; } } - if (0 != rGradient.GetBorder()) + if (bAdaptBorder) { - // apply Border if set - // NOTE: no new start node is added. The new ColorStop - // mechanism does not need entries at 0.0 and 1.0. - // In case this is needed, do that in the caller - const double fFactor(rGradient.GetBorder() * 0.01); - BColorStops aNewStops; - - for (const auto& candidate : rColorStops) - { - if (css::awt::GradientStyle_AXIAL == rGradient.GetGradientStyle()) - { - // for axial add the 'gap' at the start due to reverse used gradient - aNewStops.emplace_back((1.0 - fFactor) * candidate.getStopOffset(), candidate.getStopColor()); - } - else - { - // css::awt::GradientStyle_LINEAR - // case awt::GradientStyle_RADIAL - // case awt::GradientStyle_ELLIPTICAL - // case awt::GradientStyle_RECT - // case awt::GradientStyle_SQUARE - - // for all others add the 'gap' at the end - aNewStops.emplace_back(fFactor + (candidate.getStopOffset() * (1.0 - fFactor)), candidate.getStopColor()); - } - } - - rColorStops = aNewStops; + aWorkCopy.tryToApplyBorder(); } + + // extract ColorStops, that's all we need here + rColorStops = aWorkCopy.GetColorStops(); } /* Tooling method to synchronize the given ColorStops. The intention is that a color GradientStops and an alpha/transparence GradientStops gets synchronized - for export. - Fo the corrections the single values for color and - alpha may be used, e.g. when ColorStops is given - and not empty, but AlphaStops is empty, it will get - sycronized so that it will have the same number and - offsets in AlphaStops as in ColorStops, but with - the given SingleAlpha as value. - At return it guarantees that both have the same - number of entries with the same StopOffsets, so - that synchonized pair of ColorStops can e.g. be used - to export a Gradient with defined/adapted alpha - being 'coupled' indirectly using the - 'FillTransparenceGradient' method (at import time). - */ + for export. */ void synchronizeColorStops( BColorStops& rColorStops, BColorStops& rAlphaStops, diff --git a/include/basegfx/utils/bgradient.hxx b/include/basegfx/utils/bgradient.hxx index 4f85ed85a407..ab70d05880de 100644 --- a/include/basegfx/utils/bgradient.hxx +++ b/include/basegfx/utils/bgradient.hxx @@ -40,13 +40,10 @@ namespace basegfx Offset is defined as: - being in the range of [0.0 .. 1.0] (unit range) - - 0.0 being reserved for StartColor - - 1.0 being reserved for EndColor - - in-between offsets thus being in the range of ]0.0 .. 1.0[ - - no two equal offsets are allowed - - this is an error - - missing 1.0 entry (EndColor) is allowed - - it means that EndColor == StartColor + - offsets outside are an error + - lowest/1st value equivalent to StartColor + - highest/last value equivalent to EndColor + - missing 0.0/1.0 entries are allowed - at least one value (usually 0.0, StartColor) is required - this allows to avoid massive testing in all places where this data has to be accessed @@ -263,6 +260,19 @@ public: When also mirroring offsets a valid sort keeps valid. */ void reverseColorStops(); + + // createSpaceAtStart creates fOffset space at start by + // translating/scaling all entries to the right + void createSpaceAtStart(double fOffset); + + // removeSpaceAtStart removes fOffset space from start by + // translating/scaling entries more or equal to fOffset + // to the left. Entries less than fOffset will be removed + void removeSpaceAtStart(double fOffset); + + // try to detect if an empty/no-color-change area exists + // at the start and return offset to it. Returns 0.0 if not. + double detectPossibleOffsetAtStart() const; }; class BASEGFX_DLLPUBLIC BGradient final @@ -323,6 +333,11 @@ public: /// Tooling method to fill awt::Gradient2 from data contained in the given basegfx::BGradient css::awt::Gradient2 getAsGradient2() const; + + /// Tooling to handle border correction/integration and StartStopIntensity + void tryToRecreateBorder(basegfx::BColorStops* pAssociatedTransparencyStops); + void tryToApplyBorder(); + void tryToApplyStartEndIntensity(); }; } diff --git a/include/basegfx/utils/gradienttools.hxx b/include/basegfx/utils/gradienttools.hxx index 50d58e8a39c0..6fc51adc0e37 100644 --- a/include/basegfx/utils/gradienttools.hxx +++ b/include/basegfx/utils/gradienttools.hxx @@ -186,18 +186,23 @@ namespace basegfx namespace utils { - /* Tooling method to extract data from given awt::Gradient2 - to ColorStops, doing some corrections, partitally based + /* Tooling method to extract data from given BGradient + to ColorStops, doing some corrections, partially based on given SingleColor. + This is used for export preparations in case these exports + do neither support Start/EndIntensity nor Border settings, + both will be elliminated if possible (see below). + The BGradient rGradient and BColorStops& rColorStops + are both return parameters and may be changed. This will do quite some preparations for the gradient as follows: - It will check for single color (resetting rSingleColor when this is the case) and return with empty ColorStops - It will blend ColorStops to Intensity if StartIntensity/ - EndIntensity != 100 is set in awt::Gradient2, so applying - that value(s) to the gadient directly + EndIntensity != 100 is set in BGradient, so applying + that value(s) to the gradient directly - It will adapt to Border if Border != 0 is set at the - given awt::Gradient2, so applying that value to the gadient + given BGradient, so applying that value to the gradient directly */ BASEGFX_DLLPUBLIC void prepareColorStops( @@ -209,15 +214,15 @@ namespace basegfx The intention is that a color GradientStops and an alpha/transparence GradientStops gets synchronized for export. - Fo the corrections the single values for color and + For the corrections the single values for color and alpha may be used, e.g. when ColorStops is given and not empty, but AlphaStops is empty, it will get - sycronized so that it will have the same number and + synchronized so that it will have the same number and offsets in AlphaStops as in ColorStops, but with the given SingleAlpha as value. At return it guarantees that both have the same number of entries with the same StopOffsets, so - that synchonized pair of ColorStops can e.g. be used + that synchronized pair of ColorStops can e.g. be used to export a Gradient with defined/adapted alpha being 'coupled' indirectly using the 'FillTransparenceGradient' method (at import time). diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index d8cfc19beff3..fe00d12cf078 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -457,18 +457,11 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, // do not create gradient struct if property is not supported... if( rPropMap.supportsProperty( ShapeProperty::FillGradient ) ) { - // use awt::Gradient2, prepare ColorStops - awt::Gradient2 aGradient; + // prepare ColorStops basegfx::BColorStops aColorStops; basegfx::BColorStops aTransparencyStops; bool bContainsTransparency(false); - // set defaults - aGradient.Angle = 900; - aGradient.StartIntensity = 100; - aGradient.EndIntensity = 100; - aGradient.Style = awt::GradientStyle_LINEAR; - // convert to BColorStops, check for contained transparency for (const auto& rCandidate : maGradientProps.maGradientStops) { @@ -487,6 +480,20 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, } } + // prepare BGradient with some defaults + // CAUTION: This used awt::Gradient2 before who's empty constructor + // (see workdir/UnoApiHeadersTarget/offapi/normal/com/sun/ + // star/awt/Gradient.hpp) initializes all to zeros, so reflect + // this here. OTOH set all that were set, e.g. Start/EndIntens + // were set to 100, so just use default of BGradient constructor + basegfx::BGradient aGradient( + aColorStops, + awt::GradientStyle_LINEAR, + Degree10(900), + 0, // border + 0, // OfsX -> 0, not 50 (!) + 0); // OfsY -> 0, not 50 (!) + // "rotate with shape" set to false -> do not rotate if (!maGradientProps.moRotateWithShape.value_or(true)) { @@ -497,77 +504,61 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, { IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.value_or( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) ); sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2; - aGradient.XOffset = getLimitedValue<sal_Int16, sal_Int32>( - nCenterX / PER_PERCENT, 0, 100); + aGradient.SetXOffset(getLimitedValue<sal_Int16, sal_Int32>( + nCenterX / PER_PERCENT, 0, 100)); sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2; - aGradient.YOffset = getLimitedValue<sal_Int16, sal_Int32>( - nCenterY / PER_PERCENT, 0, 100); + aGradient.SetYOffset(getLimitedValue<sal_Int16, sal_Int32>( + nCenterY / PER_PERCENT, 0, 100)); if( maGradientProps.moGradientPath.value() == XML_circle ) { // Style should be radial at least when the horizontal center is at 50%. // Otherwise import as a linear gradient, because it is the most similar to the MSO radial style. - // aGradient.Style = awt::GradientStyle_LINEAR; - if( aGradient.XOffset == 100 && aGradient.YOffset == 100 ) - aGradient.Angle = 450; - else if( aGradient.XOffset == 0 && aGradient.YOffset == 100 ) - aGradient.Angle = 3150; - else if( aGradient.XOffset == 100 && aGradient.YOffset == 0 ) - aGradient.Angle = 1350; - else if( aGradient.XOffset == 0 && aGradient.YOffset == 0 ) - aGradient.Angle = 2250; + // aGradient.SetGradientStyle(awt::GradientStyle_LINEAR); + if( 100 == aGradient.GetXOffset() && 100 == aGradient.GetYOffset() ) + aGradient.SetAngle( Degree10(450) ); + else if( 0 == aGradient.GetXOffset() && 100 == aGradient.GetYOffset() ) + aGradient.SetAngle( Degree10(3150) ); + else if( 100 == aGradient.GetXOffset() && 0 == aGradient.GetYOffset() ) + aGradient.SetAngle( Degree10(1350) ); + else if( 0 == aGradient.GetXOffset() && 0 == aGradient.GetYOffset() ) + aGradient.SetAngle( Degree10(2250) ); else - aGradient.Style = awt::GradientStyle_RADIAL; + aGradient.SetGradientStyle(awt::GradientStyle_RADIAL); } else { - aGradient.Style = awt::GradientStyle_RECT; + aGradient.SetGradientStyle(awt::GradientStyle_RECT); } aColorStops.reverseColorStops(); + aGradient.SetColorStops(aColorStops); aTransparencyStops.reverseColorStops(); } else if (!maGradientProps.maGradientStops.empty()) { - // aGradient.Style = awt::GradientStyle_LINEAR; - sal_Int32 nShadeAngle = maGradientProps.moShadeAngle.value_or( 0 ); + // aGradient.SetGradientStyle(awt::GradientStyle_LINEAR); + sal_Int32 nShadeAngle(maGradientProps.moShadeAngle.value_or( 0 )); // Adjust for flips if ( bFlipH ) nShadeAngle = 180*60000 - nShadeAngle; if ( bFlipV ) nShadeAngle = -nShadeAngle; const sal_Int32 nDmlAngle = nShadeAngle + nShapeRotation; + // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees) - aGradient.Angle = static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 ); + aGradient.SetAngle(Degree10(static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 ))); } - // set BColorStops using UNO API - aGradient.ColorStops = aColorStops.getAsColorStopSequence(); - - // for compatibility, still set StartColor/EndColor - // NOTE: All code after adapting to multi color gradients works - // using the ColorSteps, so in principle Start/EndColor might - // be either - // (a) ignored consequently everywhere or - // (b) be set/added consequently everywhere - // since this is - in principle - redundant data. - // Be aware that e.g. cases like DrawingML::EqualGradients - // and others would have to be identified and adapted (!) - // Since awt::Gradient2 is UNO API data there might - // be cases where just awt::Gradient is transferred, so (b) - // is far better backwards compatible and thus more safe, so - // all changes will make use of additionally using/setting - // these additionally, but will only make use of the given - // ColorSteps if these are not empty, assuming that these - // already contain Start/EndColor. - // In principle that redundancy and that it is conflict-free - // could even be checked and asserted, but consequently using - // (b) methodically should be safe. - aGradient.StartColor = static_cast<sal_Int32>(::Color(aColorStops.front().getStopColor())); - aGradient.EndColor = static_cast<sal_Int32>(::Color(aColorStops.back().getStopColor())); + if (awt::GradientStyle_RECT == aGradient.GetGradientStyle()) + { + // MCGR: tdf#155362: better support border + // CAUTION: Need to handle TransparencyStops if used + aGradient.tryToRecreateBorder(aTransparencyStops.empty() ? nullptr : &aTransparencyStops); + } // push gradient or named gradient to property map - if (rPropMap.setProperty(ShapeProperty::FillGradient, aGradient)) + if (rPropMap.setProperty(ShapeProperty::FillGradient, aGradient.getAsGradient2())) { eFillStyle = FillStyle_GRADIENT; } @@ -575,8 +566,8 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, // push gradient transparency to property map if it exists if (!aTransparencyStops.empty()) { - aGradient.ColorStops = aTransparencyStops.getAsColorStopSequence(); - rPropMap.setProperty(ShapeProperty::GradientTransparency, aGradient); + aGradient.SetColorStops(aTransparencyStops); + rPropMap.setProperty(ShapeProperty::GradientTransparency, aGradient.getAsGradient2()); } } break; commit c6b90b83ad6bfaf1e95ca600ef4c5559a2a864fe Author: Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de> AuthorDate: Mon May 22 12:13:25 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:11 2023 +0200 MCGR: Check correctly for used FillTransparenceGradient To correctly check using UNO API if a FillTransparence- Gradient is used it is necessary to check if a Name for it is set. This corresponds to the IsEnabled() state of the XFillFloatTransparenceItem in the core. This was not consequently done that way and e.g. was done by checking if the FTG was 'default' in the sense that the StartColor was COL_BLACK. This was never sufficient and is not with MCGRs, too. Important in this case is the UnitTest checking for file fdo66688.docx - the re-export/roundtrip goes wrong when not doing this correctly. Change-Id: Iaf14c1e4481188124f044b4b3c8bcd6689c65aad Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152087 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 65798fa36cf6..7771caa7c92f 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -470,15 +470,22 @@ void DrawingML::WriteSolidFill( const Reference< XPropertySet >& rXPropSet ) // OOXML has no separate transparence gradient but uses transparency in the gradient stops. // So we merge transparency and color and use gradient fill in such case. basegfx::BGradient aTransparenceGradient; + OUString sFillTransparenceGradientName; bool bNeedGradientFill(false); - if (GetProperty(rXPropSet, "FillTransparenceGradient")) + if (GetProperty(rXPropSet, "FillTransparenceGradientName") + && (mAny >>= sFillTransparenceGradientName) + && !sFillTransparenceGradientName.isEmpty() + && GetProperty(rXPropSet, "FillTransparenceGradient")) { aTransparenceGradient = basegfx::BGradient(mAny); basegfx::BColor aSingleColor; bNeedGradientFill = !aTransparenceGradient.GetColorStops().isSingleColor(aSingleColor); - if (!bNeedGradientFill && aSingleColor != basegfx::BColor()) + // we no longer need to 'guess' if FillTransparenceGradient is used by + // comparing it's 1st color to COL_BLACK after having tested that the + // FillTransparenceGradientName is set + if (!bNeedGradientFill) { // Our alpha is a gray color value. const sal_uInt8 nRed(aSingleColor.getRed() * 255.0); @@ -625,13 +632,11 @@ void DrawingML::WriteGradientFill( const Reference< XPropertySet >& rXPropSet ) if (GetProperty(rXPropSet, "FillTransparenceGradientName") && (mAny >>= sFillTransparenceGradientName) - && !sFillTransparenceGradientName.isEmpty()) + && !sFillTransparenceGradientName.isEmpty() + && GetProperty(rXPropSet, "FillTransparenceGradient")) { - if (GetProperty(rXPropSet, "FillTransparenceGradient")) - { - aTransparenceGradient = basegfx::BGradient(mAny); - } - + // TransparenceGradient is only used when name is not empty + aTransparenceGradient = basegfx::BGradient(mAny); pTransparenceGradient = &aTransparenceGradient; } else if (GetProperty(rXPropSet, "FillTransparence")) @@ -5176,19 +5181,35 @@ void DrawingML::WriteFill( const Reference< XPropertySet >& xPropSet ) xPropSet->getPropertyValue( "FillStyle" ) >>= aFillStyle; // map full transparent background to no fill - if ( aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparence" ) ) - { - sal_Int16 nVal = 0; - xPropSet->getPropertyValue( "FillTransparence" ) >>= nVal; - if ( nVal == 100 ) - aFillStyle = FillStyle_NONE; - } - if (aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparenceGradient")) + if (aFillStyle == FillStyle_SOLID) { - awt::Gradient aTransparenceGradient; - mAny >>= aTransparenceGradient; - if (aTransparenceGradient.StartColor == 0xffffff && aTransparenceGradient.EndColor == 0xffffff) - aFillStyle = FillStyle_NONE; + OUString sFillTransparenceGradientName; + + if (GetProperty(xPropSet, "FillTransparenceGradientName") + && (mAny >>= sFillTransparenceGradientName) + && !sFillTransparenceGradientName.isEmpty() + && GetProperty(xPropSet, "FillTransparenceGradient")) + { + // check if a fully transparent TransparenceGradient is used + // use BGradient constructor & tooling here now + const basegfx::BGradient aTransparenceGradient(mAny); + basegfx::BColor aSingleColor; + const bool bSingleColor(aTransparenceGradient.GetColorStops().isSingleColor(aSingleColor)); + const bool bCompletelyTransparent(bSingleColor && basegfx::fTools::equal(aSingleColor.luminance(), 1.0)); + + if (bCompletelyTransparent) + { + aFillStyle = FillStyle_NONE; + } + } + else if ( GetProperty( xPropSet, "FillTransparence" ) ) + { + // check if a fully transparent FillTransparence is used + sal_Int16 nVal = 0; + xPropSet->getPropertyValue( "FillTransparence" ) >>= nVal; + if ( nVal == 100 ) + aFillStyle = FillStyle_NONE; + } } bool bUseBackground(false); diff --git a/svx/source/xoutdev/xattr.cxx b/svx/source/xoutdev/xattr.cxx index 9a3567430278..4860373836a8 100644 --- a/svx/source/xoutdev/xattr.cxx +++ b/svx/source/xoutdev/xattr.cxx @@ -2434,6 +2434,13 @@ XFillFloatTransparenceItem* XFillFloatTransparenceItem::Clone( SfxItemPool* /*pP bool XFillFloatTransparenceItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const { + if (!IsEnabled() && nMemberId == MID_NAME) + { + // make sure that we return empty string in case of query for + // "FillTransparenceGradientName" if the item is disabled + rVal <<= OUString(); + } + return XFillGradientItem::QueryValue( rVal, nMemberId ); } commit 08de3d302faf13cd7ff6a1927d07428651cafabf Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Thu Jun 1 14:24:41 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:11 2023 +0200 reduce memory overhead of AquaA11yWrapper we can allocate this internally, which reduces the number of heap allocations we need to do Change-Id: Id5298e70b6816cd65d8285ceea846dc8e9e4b39d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152489 Reviewed-by: Patrick Luby <plub...@neooffice.org> Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> (cherry picked from commit 7acc7660a752497a546263d28e82a2e8f61fd702) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152513 diff --git a/vcl/inc/osx/a11ywrapper.h b/vcl/inc/osx/a11ywrapper.h index f9b30eb98fcd..469e50820e19 100644 --- a/vcl/inc/osx/a11ywrapper.h +++ b/vcl/inc/osx/a11ywrapper.h @@ -52,7 +52,7 @@ struct ReferenceWrapper @interface AquaA11yWrapper : NSView { - ReferenceWrapper * mpReferenceWrapper; + ReferenceWrapper maReferenceWrapper; BOOL mActsAsRadioGroup; BOOL mIsTableCell; } @@ -88,7 +88,6 @@ struct ReferenceWrapper -(NSWindow*)windowForParent; -(id)initWithAccessibleContext: (css::uno::Reference < css::accessibility::XAccessibleContext >) anAccessibleContext; -(void) setDefaults: (css::uno::Reference < css::accessibility::XAccessibleContext >) rxAccessibleContext; --(void) dealloc; +(void)setPopupMenuOpen:(BOOL)popupMenuOpen; -(css::accessibility::XAccessibleAction *)accessibleAction; -(css::accessibility::XAccessibleContext *)accessibleContext; diff --git a/vcl/osx/a11ywrapper.mm b/vcl/osx/a11ywrapper.mm index 96de29e07f77..75763a65a131 100644 --- a/vcl/osx/a11ywrapper.mm +++ b/vcl/osx/a11ywrapper.mm @@ -79,34 +79,33 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(void) setDefaults: (Reference < XAccessibleContext >) rxAccessibleContext { - mpReferenceWrapper = new ReferenceWrapper; mActsAsRadioGroup = NO; - mpReferenceWrapper -> rAccessibleContext = rxAccessibleContext; + maReferenceWrapper.rAccessibleContext = rxAccessibleContext; mIsTableCell = NO; // Querying all supported interfaces try { // XAccessibleComponent - mpReferenceWrapper->rAccessibleComponent.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleComponent.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleExtendedComponent - mpReferenceWrapper->rAccessibleExtendedComponent.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleExtendedComponent.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleSelection - mpReferenceWrapper->rAccessibleSelection.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleSelection.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleTable - mpReferenceWrapper->rAccessibleTable.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleTable.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleText - mpReferenceWrapper->rAccessibleText.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleText.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleEditableText - mpReferenceWrapper->rAccessibleEditableText.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleEditableText.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleValue - mpReferenceWrapper->rAccessibleValue.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleValue.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleAction - mpReferenceWrapper->rAccessibleAction.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleAction.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleTextAttributes - mpReferenceWrapper->rAccessibleTextAttributes.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleTextAttributes.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleMultiLineText - mpReferenceWrapper->rAccessibleMultiLineText.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleMultiLineText.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleTextMarkup - mpReferenceWrapper->rAccessibleTextMarkup.set( rxAccessibleContext, UNO_QUERY ); + maReferenceWrapper.rAccessibleTextMarkup.set( rxAccessibleContext, UNO_QUERY ); // XAccessibleEventBroadcaster #if 0 /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children. @@ -137,13 +136,6 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } } --(void)dealloc { - if ( mpReferenceWrapper ) { - delete mpReferenceWrapper; - } - [ super dealloc ]; -} - #pragma mark - #pragma mark Utility Section @@ -1112,10 +1104,10 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point, } // nothing hit yet, so check ourself if ( ! hitChild.is() ) { - if ( !mpReferenceWrapper ) { + if ( !maReferenceWrapper.rAccessibleContext ) { [ self setDefaults: [ self accessibleContext ] ]; } - hitChild = hitTestRunner ( hitPoint, mpReferenceWrapper -> rAccessibleContext ); + hitChild = hitTestRunner ( hitPoint, maReferenceWrapper.rAccessibleContext ); } if ( hitChild.is() ) { wrapper = [ AquaA11yFactory wrapperForAccessibleContext: hitChild ]; @@ -1130,51 +1122,51 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point, #pragma mark Access Methods -(XAccessibleAction *)accessibleAction { - return mpReferenceWrapper -> rAccessibleAction.get(); + return maReferenceWrapper.rAccessibleAction.get(); } -(XAccessibleContext *)accessibleContext { - return mpReferenceWrapper -> rAccessibleContext.get(); + return maReferenceWrapper.rAccessibleContext.get(); } -(XAccessibleComponent *)accessibleComponent { - return mpReferenceWrapper -> rAccessibleComponent.get(); + return maReferenceWrapper.rAccessibleComponent.get(); } -(XAccessibleExtendedComponent *)accessibleExtendedComponent { - return mpReferenceWrapper -> rAccessibleExtendedComponent.get(); + return maReferenceWrapper.rAccessibleExtendedComponent.get(); } -(XAccessibleSelection *)accessibleSelection { - return mpReferenceWrapper -> rAccessibleSelection.get(); + return maReferenceWrapper.rAccessibleSelection.get(); } -(XAccessibleTable *)accessibleTable { - return mpReferenceWrapper -> rAccessibleTable.get(); + return maReferenceWrapper.rAccessibleTable.get(); } -(XAccessibleText *)accessibleText { - return mpReferenceWrapper -> rAccessibleText.get(); + return maReferenceWrapper.rAccessibleText.get(); } -(XAccessibleEditableText *)accessibleEditableText { - return mpReferenceWrapper -> rAccessibleEditableText.get(); + return maReferenceWrapper.rAccessibleEditableText.get(); } -(XAccessibleValue *)accessibleValue { - return mpReferenceWrapper -> rAccessibleValue.get(); + return maReferenceWrapper.rAccessibleValue.get(); } -(XAccessibleTextAttributes *)accessibleTextAttributes { - return mpReferenceWrapper -> rAccessibleTextAttributes.get(); + return maReferenceWrapper.rAccessibleTextAttributes.get(); } -(XAccessibleMultiLineText *)accessibleMultiLineText { - return mpReferenceWrapper -> rAccessibleMultiLineText.get(); + return maReferenceWrapper.rAccessibleMultiLineText.get(); } -(XAccessibleTextMarkup *)accessibleTextMarkup { - return mpReferenceWrapper -> rAccessibleTextMarkup.get(); + return maReferenceWrapper.rAccessibleTextMarkup.get(); } -(NSWindow*)windowForParent { diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm index 54a91571096a..08821800f5a9 100644 --- a/vcl/osx/salframeview.mm +++ b/vcl/osx/salframeview.mm @@ -619,7 +619,6 @@ static AquaSalFrame* getMouseContainerFrame() mpLastEvent = nil; mMarkedRange = NSMakeRange(NSNotFound, 0); mSelectedRange = NSMakeRange(NSNotFound, 0); - mpReferenceWrapper = nil; mpMouseEventListener = nil; mpLastSuperEvent = nil; mfLastMagnifyTime = 0.0; @@ -2055,15 +2054,14 @@ static AquaSalFrame* getMouseContainerFrame() -(css::accessibility::XAccessibleContext *)accessibleContext { - if ( !mpReferenceWrapper ) { + if ( !maReferenceWrapper.rAccessibleContext ) { // some frames never become visible .. vcl::Window *pWindow = mpFrame -> GetWindow(); if ( ! pWindow ) return nil; - mpReferenceWrapper = new ReferenceWrapper; - mpReferenceWrapper -> rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext(); - [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ]; + maReferenceWrapper.rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext(); + [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: maReferenceWrapper.rAccessibleContext ]; } return [ super accessibleContext ]; } commit cc9a6a47e47ef227cb2d93ec9d746e49c999eae2 Author: Bartosz Kosiorek <gan...@poczta.onet.pl> AuthorDate: Thu Jun 1 21:16:06 2023 +0200 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Jun 4 16:34:10 2023 +0200 tdf#143877 EMF+ Implement EmfPlusDrawCurve with cardinal spline Change-Id: I98d30b2a8ba63fdddc08668f453c5f0feeb452db Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152288 Tested-by: Jenkins Reviewed-by: Bartosz Kosiorek <gan...@poczta.onet.pl> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152552 diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx index 94c4c32f026f..03b270228628 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -81,6 +81,8 @@ namespace emfplushelper case EmfPlusRecordTypeFillPolygon: return "EmfPlusRecordTypeFillPolygon"; case EmfPlusRecordTypeDrawLines: return "EmfPlusRecordTypeDrawLines"; case EmfPlusRecordTypeFillClosedCurve: return "EmfPlusRecordTypeFillClosedCurve"; + case EmfPlusRecordTypeDrawClosedCurve: return "EmfPlusRecordTypeDrawClosedCurve"; ... etc. - the rest is truncated