summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2020-07-14 22:52:56 +0200
committerMiklos Vajna <vmiklos@collabora.com>2020-08-07 13:44:19 +0200
commit855420811e13d620dd1d0f016ac4f7da9535954c (patch)
tree789283dfffe457873303c651d8c1134f9b47df5e
parentad4f819be0502bdf30ab4644a91f53ff224d16f8 (diff)
tdf#128345 pptx export: add transparence gradient in solid fill
In case of solid color fill a transparence gradient was not saved. OOXML has no separate element for gradient transparency but has transparency in color gradient stop elements. The patch detects a transparence gradient, combines it with the fill color and exports it as gradFill element. The import was already correct, besides a wrong start or end value in case of a symmetric gradient, which becomes AXIAL in LibreOffice. (cherry picked from commit d187f22b7ff73954e1da39fb954c64bc315298cb) Conflicts: sd/qa/unit/export-tests-ooxml1.cxx Change-Id: I4243656821629f90125d0408a38165a8a29e6e24 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100282 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r--oox/source/drawingml/fillproperties.cxx6
-rw-r--r--oox/source/export/drawingml.cxx106
-rw-r--r--sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odpbin0 -> 11244 bytes
-rw-r--r--sd/qa/unit/data/odp/tdf128345_GradientAxial.odpbin0 -> 12561 bytes
-rw-r--r--sd/qa/unit/data/odp/tdf128345_GradientLinear.odpbin0 -> 13384 bytes
-rw-r--r--sd/qa/unit/data/odp/tdf128345_GradientRadial.odpbin0 -> 14774 bytes
-rw-r--r--sd/qa/unit/export-tests-ooxml1.cxx80
7 files changed, 155 insertions, 37 deletions
diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx
index 963c4009becf..f203e9e2823e 100644
--- a/oox/source/drawingml/fillproperties.cxx
+++ b/oox/source/drawingml/fillproperties.cxx
@@ -537,10 +537,8 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap,
aGradient.StartColor = sal_Int32(aStartColor.getColor( rGraphicHelper, nPhClr ));
aGradient.EndColor = sal_Int32(aEndColor.getColor( rGraphicHelper, nPhClr ));
- if( aStartColor.hasTransparency() )
- nStartTrans = aStartColor.getTransparency()*255/100;
- if( aEndColor.hasTransparency() )
- nEndTrans = aEndColor.getTransparency()*255/100;
+ nStartTrans = aStartColor.hasTransparency() ? aStartColor.getTransparency()*255/100 : 0;
+ nEndTrans = aEndColor.hasTransparency() ? aEndColor.getTransparency()*255/100 : 0;
aGradient.Border = rtl::math::round(100*nBorder);
}
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 8a49546c94bd..14910f759598 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -397,8 +397,38 @@ void DrawingML::WriteSolidFill( const Reference< XPropertySet >& rXPropSet )
nAlpha = (MAX_PERCENT - ( PER_PERCENT * nTransparency ) );
}
+ // 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.
+ awt::Gradient aTransparenceGradient;
+ bool bNeedGradientFill(false);
+ if (GetProperty(rXPropSet, "FillTransparenceGradient"))
+ {
+ mAny >>= aTransparenceGradient;
+ if (aTransparenceGradient.StartColor != aTransparenceGradient.EndColor)
+ bNeedGradientFill = true;
+ else if (aTransparenceGradient.StartColor != 0)
+ nAlpha = GetAlphaFromTransparenceGradient(aTransparenceGradient, true);
+ }
+
// write XML
- if ( nFillColor != nOriginalColor )
+ if (bNeedGradientFill)
+ {
+ awt::Gradient aPseudoColorGradient;
+ aPseudoColorGradient.XOffset = aTransparenceGradient.XOffset;
+ aPseudoColorGradient.YOffset = aTransparenceGradient.YOffset;
+ aPseudoColorGradient.StartIntensity = 100;
+ aPseudoColorGradient.EndIntensity = 100;
+ aPseudoColorGradient.Angle = aTransparenceGradient.Angle;
+ aPseudoColorGradient.Border = aTransparenceGradient.Border;
+ aPseudoColorGradient.Style = aTransparenceGradient.Style;
+ aPseudoColorGradient.StartColor = nFillColor;
+ aPseudoColorGradient.EndColor = nFillColor;
+ aPseudoColorGradient.StepCount = aTransparenceGradient.StepCount;
+ mpFS->startElementNS(XML_a, XML_gradFill, XML_rotWithShape, "0");
+ WriteGradientFill(aPseudoColorGradient, aTransparenceGradient);
+ mpFS->endElementNS( XML_a, XML_gradFill );
+ }
+ else if ( nFillColor != nOriginalColor )
{
// the user has set a different color for the shape
WriteSolidFill( ::Color(nFillColor & 0xffffff), nAlpha );
@@ -578,25 +608,25 @@ void DrawingML::WriteGrabBagGradientFill( const Sequence< PropertyValue >& aGrad
void DrawingML::WriteGradientFill(awt::Gradient rGradient, awt::Gradient rTransparenceGradient,
const uno::Reference<beans::XPropertySet>& rXPropSet)
{
+ sal_Int32 nStartAlpha;
+ sal_Int32 nEndAlpha;
+ if( rXPropSet.is() && GetProperty(rXPropSet, "FillTransparence") )
+ {
+ sal_Int32 nTransparency = 0;
+ mAny >>= nTransparency;
+ nStartAlpha = nEndAlpha = (MAX_PERCENT - (PER_PERCENT * nTransparency));
+ }
+ else
+ {
+ nStartAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, true);
+ nEndAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, false);
+ }
switch( rGradient.Style )
{
default:
case awt::GradientStyle_LINEAR:
{
mpFS->startElementNS(XML_a, XML_gsLst);
- sal_Int32 nStartAlpha;
- sal_Int32 nEndAlpha;
- if( rXPropSet.is() && GetProperty(rXPropSet, "FillTransparence") )
- {
- sal_Int32 nTransparency = 0;
- mAny >>= nTransparency;
- nStartAlpha = nEndAlpha = (MAX_PERCENT - (PER_PERCENT * nTransparency));
- }
- else
- {
- nStartAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, true);
- nEndAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, false);
- }
WriteGradientStop(rGradient.Border, ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity),
nStartAlpha);
WriteGradientStop(100, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity),
@@ -611,23 +641,22 @@ void DrawingML::WriteGradientFill(awt::Gradient rGradient, awt::Gradient rTransp
case awt::GradientStyle_AXIAL:
{
mpFS->startElementNS(XML_a, XML_gsLst);
- sal_Int32 nStartAlpha;
- sal_Int32 nEndAlpha;
- if (rXPropSet.is() && GetProperty(rXPropSet, "FillTransparence"))
- {
- sal_Int32 nTransparency = 0;
- mAny >>= nTransparency;
- nStartAlpha = nEndAlpha = (MAX_PERCENT - (PER_PERCENT * nTransparency));
- }
- else
- {
- nStartAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, true);
- nEndAlpha = GetAlphaFromTransparenceGradient(rTransparenceGradient, false);
- }
WriteGradientStop(0, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity),
nEndAlpha);
+ if (rGradient.Border > 0 && rGradient.Border < 100)
+ {
+ WriteGradientStop(rGradient.Border/2,
+ ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity),
+ nEndAlpha);
+ }
WriteGradientStop(50, ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity),
nStartAlpha);
+ if (rGradient.Border > 0 && rGradient.Border < 100)
+ {
+ WriteGradientStop(100 - rGradient.Border/2,
+ ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity),
+ nEndAlpha);
+ }
WriteGradientStop(100, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity),
nEndAlpha);
mpFS->endElementNS(XML_a, XML_gsLst);
@@ -643,15 +672,19 @@ void DrawingML::WriteGradientFill(awt::Gradient rGradient, awt::Gradient rTransp
case awt::GradientStyle_SQUARE:
{
mpFS->startElementNS(XML_a, XML_gsLst);
- WriteGradientStop(0, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity));
+ WriteGradientStop(0, ColorWithIntensity(rGradient.EndColor, rGradient.EndIntensity),
+ nEndAlpha);
if (rGradient.Border > 0 && rGradient.Border < 100)
+ {
// Map border to an additional gradient stop, which has the
// same color as the final stop.
- WriteGradientStop(
- 100 - rGradient.Border,
- ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity));
+ WriteGradientStop(100 - rGradient.Border,
+ ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity),
+ nStartAlpha);
+ }
WriteGradientStop(100,
- ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity));
+ ColorWithIntensity(rGradient.StartColor, rGradient.StartIntensity),
+ nStartAlpha);
mpFS->endElementNS(XML_a, XML_gsLst);
WriteGradientPath(rGradient, mpFS, rGradient.Style == awt::GradientStyle_RADIAL || rGradient.Style == awt::GradientStyle_ELLIPTICAL);
@@ -3484,14 +3517,21 @@ void DrawingML::WriteFill( const Reference< XPropertySet >& xPropSet )
FillStyle aFillStyle( FillStyle_NONE );
xPropSet->getPropertyValue( "FillStyle" ) >>= aFillStyle;
+ // map full transparent background to no fill
if ( aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparence" ) )
{
- // map full transparent background to no fill
sal_Int16 nVal = 0;
xPropSet->getPropertyValue( "FillTransparence" ) >>= nVal;
if ( nVal == 100 )
aFillStyle = FillStyle_NONE;
}
+ if (aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparenceGradient"))
+ {
+ awt::Gradient aTransparenceGradient;
+ mAny >>= aTransparenceGradient;
+ if (aTransparenceGradient.StartColor == 0xffffff && aTransparenceGradient.EndColor == 0xffffff)
+ aFillStyle = FillStyle_NONE;
+ }
switch( aFillStyle )
{
diff --git a/sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp b/sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp
new file mode 100644
index 000000000000..904490d4313f
--- /dev/null
+++ b/sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp
Binary files differ
diff --git a/sd/qa/unit/data/odp/tdf128345_GradientAxial.odp b/sd/qa/unit/data/odp/tdf128345_GradientAxial.odp
new file mode 100644
index 000000000000..55b8ec1aac60
--- /dev/null
+++ b/sd/qa/unit/data/odp/tdf128345_GradientAxial.odp
Binary files differ
diff --git a/sd/qa/unit/data/odp/tdf128345_GradientLinear.odp b/sd/qa/unit/data/odp/tdf128345_GradientLinear.odp
new file mode 100644
index 000000000000..1eadfa11f08b
--- /dev/null
+++ b/sd/qa/unit/data/odp/tdf128345_GradientLinear.odp
Binary files differ
diff --git a/sd/qa/unit/data/odp/tdf128345_GradientRadial.odp b/sd/qa/unit/data/odp/tdf128345_GradientRadial.odp
new file mode 100644
index 000000000000..634d1dc1bd5f
--- /dev/null
+++ b/sd/qa/unit/data/odp/tdf128345_GradientRadial.odp
Binary files differ
diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx
index f7cec3010dc7..74620cba8517 100644
--- a/sd/qa/unit/export-tests-ooxml1.cxx
+++ b/sd/qa/unit/export-tests-ooxml1.cxx
@@ -91,6 +91,10 @@ public:
void testRoundtripPrstDash();
void testDashOnHairline();
void testCustomshapeBitmapfillSrcrect();
+ void testTdf128345FullTransparentGradient();
+ void testTdf128345GradientLinear();
+ void testTdf128345GradientRadial();
+ void testTdf128345GradientAxial();
CPPUNIT_TEST_SUITE(SdOOXMLExportTest1);
@@ -131,6 +135,10 @@ public:
CPPUNIT_TEST(testRoundtripPrstDash);
CPPUNIT_TEST(testDashOnHairline);
CPPUNIT_TEST(testCustomshapeBitmapfillSrcrect);
+ CPPUNIT_TEST(testTdf128345FullTransparentGradient);
+ CPPUNIT_TEST(testTdf128345GradientLinear);
+ CPPUNIT_TEST(testTdf128345GradientRadial);
+ CPPUNIT_TEST(testTdf128345GradientAxial);
CPPUNIT_TEST_SUITE_END();
@@ -1095,6 +1103,78 @@ void SdOOXMLExportTest1::testCustomshapeBitmapfillSrcrect()
CPPUNIT_ASSERT_EQUAL(4.0, fRightPercent);
}
+void SdOOXMLExportTest1::testTdf128345FullTransparentGradient()
+{
+ ::sd::DrawDocShellRef xDocShRef
+ = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_FullTransparentGradient.odp"), ODP);
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+ xDocShRef->DoClose();
+
+ // Make sure the shape has no fill. Without the patch, fill was solid red.
+ xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml");
+ const OString sPathStart("//p:sld/p:cSld/p:spTree/p:sp/p:spPr");
+ assertXPath(pXmlDoc, sPathStart + "/a:noFill");
+}
+
+void SdOOXMLExportTest1::testTdf128345GradientLinear()
+{
+ ::sd::DrawDocShellRef xDocShRef
+ = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_GradientLinear.odp"), ODP);
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+ xDocShRef->DoClose();
+
+ // Make sure the shape has a lin fill. Without the patch, fill was solid red.
+ xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml");
+ const OString sPathStart("//p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill");
+ assertXPath(pXmlDoc, sPathStart + "/a:lin", "ang", "3600000");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs",2);
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]", "pos", "25000");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr", "val", "ff0000");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", "val", "20000");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]", "pos", "100000");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr", "val", "ff0000");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "80000");
+}
+
+void SdOOXMLExportTest1::testTdf128345GradientRadial()
+{
+ ::sd::DrawDocShellRef xDocShRef
+ = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_GradientRadial.odp"), ODP);
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+ xDocShRef->DoClose();
+
+ // Make sure the shape has transparency. In OOXML alpha means 'opacity' with default
+ // 100000 for full opak, so only the full transparency with val 0 should be written.
+ xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml");
+ const OString sPathStart("//p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs",2);
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr", "val", "ff0000");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", 0);
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr", "val", "ffffff");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "0");
+}
+
+void SdOOXMLExportTest1::testTdf128345GradientAxial()
+{
+ // Without the patch, symmtetric linear gradient with full transparence outside and
+ // full opak in the middle were imported as full transparent.
+ ::sd::DrawDocShellRef xDocShRef
+ = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_GradientAxial.odp"), ODP);
+ xDocShRef = saveAndReload(xDocShRef.get(), PPTX);
+ uno::Reference<beans::XPropertySet> xShapePropSet(getShapeFromPage(0, 0, xDocShRef));
+
+ awt::Gradient aTransparenceGradient;
+ xShapePropSet->getPropertyValue("FillTransparenceGradient") >>= aTransparenceGradient;
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0x000000), aTransparenceGradient.StartColor);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0xffffff), aTransparenceGradient.EndColor);
+ CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_AXIAL, aTransparenceGradient.Style);
+
+ xDocShRef->DoClose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest1);
CPPUNIT_PLUGIN_IMPLEMENT();