MCGR: Use tryToRecreateBorder too for transparency
This is similar to 'Use tryToRecreateBorder for better BW comp with LO'
(see commit 8259a99f41
), 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.henschel@t-online.de>
This commit is contained in:
BIN
xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx
Normal file
BIN
xmloff/qa/unit/data/MCGR_TransparencyBorder_restoration.pptx
Normal file
Binary file not shown.
@@ -553,6 +553,43 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testBorderRestoration)
|
|||||||
SetODFDefaultVersion(nCurrentODFVersion);
|
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();
|
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||||
|
|
||||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <com/sun/star/awt/Gradient2.hpp>
|
#include <com/sun/star/awt/Gradient2.hpp>
|
||||||
|
|
||||||
|
#include <basegfx/utils/bgradient.hxx>
|
||||||
#include <comphelper/documentconstants.hxx>
|
#include <comphelper/documentconstants.hxx>
|
||||||
#include <rtl/ustrbuf.hxx>
|
#include <rtl/ustrbuf.hxx>
|
||||||
#include <rtl/ustring.hxx>
|
#include <rtl/ustring.hxx>
|
||||||
@@ -169,19 +170,26 @@ void XMLTransGradientStyleExport::exportXML(
|
|||||||
const OUString& rStrName,
|
const OUString& rStrName,
|
||||||
const uno::Any& rValue )
|
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() )
|
if( rStrName.isEmpty() )
|
||||||
return;
|
return;
|
||||||
|
if (!rValue.has<css::awt::Gradient2>() && !rValue.has<css::awt::Gradient>())
|
||||||
if( !(rValue >>= aGradient) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
basegfx::BGradient aGradient(rValue);
|
||||||
|
|
||||||
|
// ToDo: aGradient.tryToConvertToAxial();
|
||||||
|
|
||||||
|
aGradient.tryToRecreateBorder(nullptr);
|
||||||
|
|
||||||
OUString aStrValue;
|
OUString aStrValue;
|
||||||
OUStringBuffer aOut;
|
OUStringBuffer aOut;
|
||||||
|
|
||||||
// Style
|
// Style
|
||||||
if( !SvXMLUnitConverter::convertEnum( aOut, aGradient.Style, pXML_GradientStyle_Enum ) )
|
if (!SvXMLUnitConverter::convertEnum(aOut, aGradient.GetGradientStyle(),
|
||||||
|
pXML_GradientStyle_Enum))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
@@ -197,71 +205,75 @@ void XMLTransGradientStyleExport::exportXML(
|
|||||||
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue );
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue );
|
||||||
|
|
||||||
// Center x/y
|
// Center x/y
|
||||||
if( aGradient.Style != awt::GradientStyle_LINEAR &&
|
if (awt::GradientStyle_LINEAR != aGradient.GetGradientStyle()
|
||||||
aGradient.Style != awt::GradientStyle_AXIAL )
|
&& awt::GradientStyle_AXIAL != aGradient.GetGradientStyle())
|
||||||
{
|
{
|
||||||
::sax::Converter::convertPercent(aOut, aGradient.XOffset);
|
::sax::Converter::convertPercent(aOut, aGradient.GetXOffset());
|
||||||
aStrValue = aOut.makeStringAndClear();
|
aStrValue = aOut.makeStringAndClear();
|
||||||
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue );
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue );
|
||||||
|
|
||||||
::sax::Converter::convertPercent(aOut, aGradient.YOffset);
|
::sax::Converter::convertPercent(aOut, aGradient.GetYOffset());
|
||||||
aStrValue = aOut.makeStringAndClear();
|
aStrValue = aOut.makeStringAndClear();
|
||||||
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue );
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transparency start
|
// LO uses a gray color as transparency. ODF uses opacity in range [0%,100%].
|
||||||
Color aColor(ColorTransparency, aGradient.StartColor);
|
// Default 100% opacity.
|
||||||
sal_Int32 aStartValue = 100 - static_cast<sal_Int32>(((aColor.GetRed() + 1) * 100) / 255);
|
double fOpacityStartPerc = 100.0;
|
||||||
::sax::Converter::convertPercent( aOut, aStartValue );
|
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();
|
aStrValue = aOut.makeStringAndClear();
|
||||||
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START, aStrValue );
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START, aStrValue );
|
||||||
|
|
||||||
// Transparency end
|
// Opacity end
|
||||||
aColor = Color(ColorTransparency, aGradient.EndColor);
|
::sax::Converter::convertPercent( aOut, static_cast<sal_Int32>(std::lround(fOpacityEndPerc)));
|
||||||
sal_Int32 aEndValue = 100 - static_cast<sal_Int32>(((aColor.GetRed() + 1) * 100) / 255);
|
|
||||||
::sax::Converter::convertPercent( aOut, aEndValue );
|
|
||||||
aStrValue = aOut.makeStringAndClear();
|
aStrValue = aOut.makeStringAndClear();
|
||||||
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END, aStrValue );
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END, aStrValue );
|
||||||
|
|
||||||
// Angle
|
// 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();
|
aStrValue = aOut.makeStringAndClear();
|
||||||
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue );
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Border
|
// Border
|
||||||
::sax::Converter::convertPercent( aOut, aGradient.Border );
|
::sax::Converter::convertPercent(aOut, aGradient.GetBorder());
|
||||||
aStrValue = aOut.makeStringAndClear();
|
aStrValue = aOut.makeStringAndClear();
|
||||||
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue );
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue );
|
||||||
|
|
||||||
// ctor writes start tag. End-tag is written by destructor at block end.
|
// ctor writes start tag. End-tag is written by destructor at block end.
|
||||||
SvXMLElementExport rElem( rExport,
|
SvXMLElementExport rElem(rExport, XML_NAMESPACE_DRAW, XML_OPACITY, true, false);
|
||||||
XML_NAMESPACE_DRAW, XML_OPACITY,
|
|
||||||
true, false );
|
|
||||||
|
|
||||||
// Write child elements <loext:opacity-stop>
|
// Write child elements <loext:opacity-stop>
|
||||||
// Do not export in standard ODF 1.3 or older.
|
// Do not export in standard ODF 1.3 or older.
|
||||||
if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
|
if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
|
||||||
return;
|
return;
|
||||||
sal_Int32 nCount = aGradient.ColorStops.getLength();
|
if (aGradient.GetColorStops().empty())
|
||||||
if (nCount == 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double fPreviousOffset = 0.0;
|
double fPreviousOffset = 0.0;
|
||||||
for (auto& aCandidate : aGradient.ColorStops)
|
for (auto& aCandidate : aGradient.GetColorStops())
|
||||||
{
|
{
|
||||||
// Attribute svg:offset. Make sure offsets are increasing.
|
// 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)
|
if (fOffset < fPreviousOffset)
|
||||||
fOffset = fPreviousOffset;
|
fOffset = fPreviousOffset;
|
||||||
rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset));
|
rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset));
|
||||||
fPreviousOffset = fOffset;
|
fPreviousOffset = fOffset;
|
||||||
|
|
||||||
// Attribute svg:stop-opacity, data type zeroToOneDecimal
|
// Attribute svg:stop-opacity, data type zeroToOneDecimal
|
||||||
rendering::RGBColor aDecimalColor = aCandidate.StopColor;
|
double fOpacity = std::clamp<double>(1.0 - aCandidate.getStopColor().getRed(), 0.0, 1.0);
|
||||||
// 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));
|
rExport.AddAttribute(XML_NAMESPACE_SVG, XML_STOP_OPACITY, OUString::number(fOpacity));
|
||||||
|
|
||||||
// write opacity stop element
|
// write opacity stop element
|
||||||
|
Reference in New Issue
Block a user