summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2020-07-27 00:31:04 +0200
committerRegina Henschel <rb.henschel@t-online.de>2020-08-09 12:15:54 +0200
commitacfd9e9ca2dfd76536c072e21c65cb3efc6aac80 (patch)
tree7edc5e9a88d7c39f85655444be206bc588946818
parent3d44c6a49b20415616dab7a2de2820da5efab309 (diff)
tdf#128345 PPTX: add transparence gradient for fill in chart
Export cases: Add transparence gradient on solid color fill by treating the color fill as gradient with identical start and end color. Add solid transparence on color gradient, by treating transparence as gradient. Import: Add missing property PROP_FillTransparenceGradientName to spnCommonPropIds so that it is available in spObjTypeFormatEntries. Otherwise transparence gradients will be skipped on import. Change-Id: I56218ec1afcc5bd1ce0324ca50c03e0b44f76c58 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99464 Tested-by: Jenkins Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
-rw-r--r--include/oox/export/chartexport.hxx1
-rw-r--r--oox/source/drawingml/chart/objectformatter.cxx2
-rw-r--r--oox/source/export/chartexport.cxx103
-rw-r--r--sd/qa/unit/data/odp/tdf128345_ChartArea_CG_TS.odpbin0 -> 19486 bytes
-rw-r--r--sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odpbin0 -> 16551 bytes
-rw-r--r--sd/qa/unit/data/odp/tdf128345_Legend_CS_TG_axial.odpbin0 -> 15174 bytes
-rw-r--r--sd/qa/unit/export-tests-ooxml1.cxx120
7 files changed, 220 insertions, 6 deletions
diff --git a/include/oox/export/chartexport.hxx b/include/oox/export/chartexport.hxx
index 194e15628aef..5faaf42cb1d1 100644
--- a/include/oox/export/chartexport.hxx
+++ b/include/oox/export/chartexport.hxx
@@ -141,6 +141,7 @@ private:
void exportPlotArea( const css::uno::Reference<
css::chart::XChartDocument >& rChartDoc );
void exportFill( const css::uno::Reference< css::beans::XPropertySet >& xPropSet );
+ void exportSolidFill(const css::uno::Reference<css::beans::XPropertySet>& xPropSet);
void exportGradientFill( const css::uno::Reference< css::beans::XPropertySet >& xPropSet );
void exportBitmapFill( const css::uno::Reference< css::beans::XPropertySet >& xPropSet );
void exportHatch(const css::uno::Reference<css::beans::XPropertySet>& xPropSet);
diff --git a/oox/source/drawingml/chart/objectformatter.cxx b/oox/source/drawingml/chart/objectformatter.cxx
index 326f632e84b3..fd580742c97a 100644
--- a/oox/source/drawingml/chart/objectformatter.cxx
+++ b/oox/source/drawingml/chart/objectformatter.cxx
@@ -447,7 +447,7 @@ const ShapePropertyIds spnCommonPropIds =
{
PROP_LineStyle, PROP_LineWidth, PROP_LineColor, PROP_LineTransparence, PROP_LineDashName,
PROP_LineCap, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID,
- PROP_FillStyle, PROP_FillColor, PROP_FillTransparence, PROP_INVALID, PROP_FillGradientName,
+ PROP_FillStyle, PROP_FillColor, PROP_FillTransparence, PROP_FillTransparenceGradientName, PROP_FillGradientName,
PROP_FillBitmapName, PROP_FillBitmapMode, PROP_FillBitmapSizeX, PROP_FillBitmapSizeY,
PROP_FillBitmapPositionOffsetX, PROP_FillBitmapPositionOffsetY, PROP_FillBitmapRectanglePoint,
PROP_FillHatchName, PROP_FillBackground
diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx
index 5f8ea80f8c9b..db4af798c867 100644
--- a/oox/source/export/chartexport.cxx
+++ b/oox/source/export/chartexport.cxx
@@ -429,6 +429,14 @@ static sal_Int32 lcl_generateRandomValue()
return comphelper::rng::uniform_int_distribution(0, 100000000-1);
}
+static sal_Int32 lcl_getAlphaFromTransparenceGradient(const awt::Gradient& rGradient, bool bStart)
+{
+ // Our alpha is a gray color value.
+ sal_uInt8 nRed = ::Color(bStart ? rGradient.StartColor : rGradient.EndColor).GetRed();
+ // drawingML alpha is a percentage on a 0..100000 scale.
+ return (255 - nRed) * oox::drawingml::MAX_PERCENT / 255;
+}
+
ChartExport::ChartExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, Reference< frame::XModel > const & xModel, XmlFilterBase* pFB, DocumentType eDocumentType )
: DrawingML( std::move(pFS), pFB, eDocumentType )
, mnXmlNamespace( nXmlNamespace )
@@ -1560,12 +1568,38 @@ void ChartExport::exportManualLayout(const css::chart2::RelativePosition& rPos,
void ChartExport::exportFill( const Reference< XPropertySet >& xPropSet )
{
- if ( !GetProperty( xPropSet, "FillStyle" ) )
+ // Similar to DrawingML::WriteFill, but gradient access via name
+ if (!GetProperty( xPropSet, "FillStyle" ))
return;
- FillStyle aFillStyle( FillStyle_NONE );
- xPropSet->getPropertyValue( "FillStyle" ) >>= aFillStyle;
+ FillStyle aFillStyle(FillStyle_NONE);
+ 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;
+ }
+ OUString sFillTransparenceGradientName;
+ if (aFillStyle == FillStyle_SOLID
+ && (xPropSet->getPropertyValue("FillTransparenceGradientName") >>= sFillTransparenceGradientName)
+ && !sFillTransparenceGradientName.isEmpty())
+ {
+ awt::Gradient aTransparenceGradient;
+ uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
+ uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
+ uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
+ rTransparenceValue >>= aTransparenceGradient;
+ if (aTransparenceGradient.StartColor == 0xffffff && aTransparenceGradient.EndColor == 0xffffff)
+ aFillStyle = FillStyle_NONE;
+ }
switch( aFillStyle )
{
+ case FillStyle_SOLID:
+ exportSolidFill(xPropSet);
+ break;
case FillStyle_GRADIENT :
exportGradientFill( xPropSet );
break;
@@ -1574,12 +1608,71 @@ void ChartExport::exportFill( const Reference< XPropertySet >& xPropSet )
break;
case FillStyle_HATCH:
exportHatch(xPropSet);
- break;
+ break;
+ case FillStyle_NONE:
+ mpFS->singleElementNS(XML_a, XML_noFill);
+ break;
default:
- WriteFill( xPropSet );
+ ;
}
}
+void ChartExport::exportSolidFill(const Reference< XPropertySet >& xPropSet)
+{
+ // Similar to DrawingML::WriteSolidFill, but gradient access via name
+ // and currently no InteropGrabBag
+ // get fill color
+ if (!GetProperty( xPropSet, "FillColor" ))
+ return;
+ sal_uInt32 nFillColor = mAny.get<sal_uInt32>();
+
+ sal_Int32 nAlpha = MAX_PERCENT;
+ if (GetProperty( xPropSet, "FillTransparence" ))
+ {
+ sal_Int32 nTransparency = 0;
+ mAny >>= nTransparency;
+ // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
+ 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);
+ OUString sFillTransparenceGradientName;
+ if ((xPropSet->getPropertyValue("FillTransparenceGradientName") >>= sFillTransparenceGradientName)
+ && !sFillTransparenceGradientName.isEmpty())
+ {
+ uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
+ uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
+ uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
+ rTransparenceValue >>= aTransparenceGradient;
+ if (aTransparenceGradient.StartColor != aTransparenceGradient.EndColor)
+ bNeedGradientFill = true;
+ else if (aTransparenceGradient.StartColor != 0)
+ nAlpha = lcl_getAlphaFromTransparenceGradient(aTransparenceGradient, true);
+ }
+ // write XML
+ 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
+ WriteSolidFill(::Color(nFillColor & 0xffffff), nAlpha);
+}
+
void ChartExport::exportHatch( const Reference< XPropertySet >& xPropSet )
{
if (!xPropSet.is())
diff --git a/sd/qa/unit/data/odp/tdf128345_ChartArea_CG_TS.odp b/sd/qa/unit/data/odp/tdf128345_ChartArea_CG_TS.odp
new file mode 100644
index 000000000000..754e71d51222
--- /dev/null
+++ b/sd/qa/unit/data/odp/tdf128345_ChartArea_CG_TS.odp
Binary files differ
diff --git a/sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odp b/sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odp
new file mode 100644
index 000000000000..4c09ebb7bb34
--- /dev/null
+++ b/sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odp
Binary files differ
diff --git a/sd/qa/unit/data/odp/tdf128345_Legend_CS_TG_axial.odp b/sd/qa/unit/data/odp/tdf128345_Legend_CS_TG_axial.odp
new file mode 100644
index 000000000000..bfcd8a5dd5c9
--- /dev/null
+++ b/sd/qa/unit/data/odp/tdf128345_Legend_CS_TG_axial.odp
Binary files differ
diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx
index f1b8bcca5b6d..210337794ce9 100644
--- a/sd/qa/unit/export-tests-ooxml1.cxx
+++ b/sd/qa/unit/export-tests-ooxml1.cxx
@@ -98,6 +98,9 @@ public:
void testTdf128345GradientRadial();
void testTdf128345GradientAxial();
void testTdf134969TransparencyOnColorGradient();
+ void testTdf128345ChartArea_CG_TS();
+ void testTdf128345Chart_CS_TG();
+ void testTdf128345Legend_CS_TG_axial();
CPPUNIT_TEST_SUITE(SdOOXMLExportTest1);
@@ -145,6 +148,9 @@ public:
CPPUNIT_TEST(testTdf128345GradientRadial);
CPPUNIT_TEST(testTdf128345GradientAxial);
CPPUNIT_TEST(testTdf134969TransparencyOnColorGradient);
+ CPPUNIT_TEST(testTdf128345ChartArea_CG_TS);
+ CPPUNIT_TEST(testTdf128345Chart_CS_TG);
+ CPPUNIT_TEST(testTdf128345Legend_CS_TG_axial);
CPPUNIT_TEST_SUITE_END();
@@ -167,6 +173,11 @@ public:
{ "a14", "http://schemas.microsoft.com/office/drawing/2010/main" },
{ "wps", "http://schemas.microsoft.com/office/word/2010/wordprocessingShape" },
{ "wpg", "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" },
+ // ODF
+ { "office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0" },
+ { "draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"},
+ { "style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0" },
+ { "chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0" },
};
for (size_t i = 0; i < SAL_N_ELEMENTS(namespaces); ++i)
{
@@ -1230,6 +1241,115 @@ void SdOOXMLExportTest1::testTdf134969TransparencyOnColorGradient()
assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "60000");
}
+void SdOOXMLExportTest1::testTdf128345ChartArea_CG_TS()
+{
+ // chart area with color gradient and solid transparency
+ // Without the patch the transparency was lost.
+ ::sd::DrawDocShellRef xDocShRef
+ = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_ChartArea_CG_TS.odp"), ODP);
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+ // Make sure the chart area has a transparency in gradient stops in saved file.
+ xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/charts/chart1.xml"); // <-- does not exists, is chart2.xml ??
+ OString sPathStart("//c:chartSpace/c:spPr/a:gradFill");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs",2);
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", "val", "30000");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "30000");
+
+ // Make sure chart area has transparency in the reloaded document. Currently transparency is
+ // always imported as gradient. Change test, when import creates solid transparency.
+ // I use the saved odp file for testing, because I don't know how to access the chart
+ // from the active document in a unit test.
+ utl::TempFile tempFile2;
+ xDocShRef = saveAndReload(xDocShRef.get(), ODP, &tempFile2);
+ xmlDocUniquePtr pXmlDoc2 = parseExport(tempFile2, "Object 1/styles.xml");
+ sPathStart = "//office:document-styles/office:styles";
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:start='30%']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:end='30%']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:border='20%']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:name='msTransGradient_20_1']");
+
+ xmlDocUniquePtr pXmlDoc3 = parseExport(tempFile2, "Object 1/content.xml");
+ sPathStart = "//office:document-content/office:automatic-styles/style:style[@style:name='ch1']";
+ assertXPath(pXmlDoc3, sPathStart + "/style:graphic-properties[@draw:opacity-name='msTransGradient_20_1']");
+ sPathStart = "//office:document-content/office:body/office:chart";
+ assertXPath(pXmlDoc3, sPathStart + "/chart:chart[@chart:style-name='ch1']");
+
+ xDocShRef->DoClose();
+}
+
+void SdOOXMLExportTest1::testTdf128345Chart_CS_TG()
+{
+ // chart with solid color and transparency gradient
+ // Without the patch the transparency was lost.
+ ::sd::DrawDocShellRef xDocShRef
+ = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odp"), ODP);
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+ // Make sure the chart area has a transparency in gradient stops in saved file.
+ xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/charts/chart2.xml"); // <-- why not chart1.xml ??
+ OString sPathStart("//c:chartSpace/c:chart/c:plotArea/c:spPr/a:gradFill");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs",2); //linear
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", "val", "0"); // 100% transparent
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", 0); // no element for 0% transparent
+
+ // Make sure chart has transparency in the reloaded document.
+ // I use the saved odp file for testing, because I don't know how to access the chart
+ // from the active document in a unit test.
+ utl::TempFile tempFile2;
+ xDocShRef = saveAndReload(xDocShRef.get(), ODP, &tempFile2);
+ xmlDocUniquePtr pXmlDoc2 = parseExport(tempFile2, "Object 1/styles.xml");
+ sPathStart = "//office:document-styles/office:styles";
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:style='linear']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:start='0%']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:end='100%']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:name='msTransGradient_20_1']");
+
+ xmlDocUniquePtr pXmlDoc3 = parseExport(tempFile2, "Object 1/content.xml");
+ sPathStart = "//office:document-content/office:automatic-styles/style:style[@style:name='ch8']";
+ assertXPath(pXmlDoc3, sPathStart + "/style:graphic-properties[@draw:opacity-name='msTransGradient_20_1']");
+ sPathStart = "//office:document-content/office:body/office:chart/chart:chart/chart:plot-area";
+ assertXPath(pXmlDoc3, sPathStart + "/chart:wall[@chart:style-name='ch8']");
+
+ xDocShRef->DoClose();
+}
+
+void SdOOXMLExportTest1::testTdf128345Legend_CS_TG_axial()
+{
+ // legend with solid color and transparency gradient
+ // Without the patch the transparency was lost.
+ ::sd::DrawDocShellRef xDocShRef
+ = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf128345_Legend_CS_TG_axial.odp"), ODP);
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+ // Make sure the legend has a transparency in gradient stops in saved file.
+ xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/charts/chart3.xml");
+ OString sPathStart("//c:chartSpace/c:chart/c:legend/c:spPr/a:gradFill");
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs",3); // axial
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[1]/a:srgbClr/a:alpha", 0); // no element for 0% transparent
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[2]/a:srgbClr/a:alpha", "val", "0"); // 100% transparent
+ assertXPath(pXmlDoc, sPathStart + "/a:gsLst/a:gs[3]/a:srgbClr/a:alpha", 0); // no element for 0% transparent
+
+ // Make sure legend has axial transparency in the reloaded document.
+ // I use the saved odp file for testing, because I don't know how to access the chart
+ // from the active document in a unit test.
+ utl::TempFile tempFile2;
+ xDocShRef = saveAndReload(xDocShRef.get(), ODP, &tempFile2);
+ xmlDocUniquePtr pXmlDoc2 = parseExport(tempFile2, "Object 1/styles.xml");
+ sPathStart = "//office:document-styles/office:styles";
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:style='axial']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:start='0%']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:end='100%']");
+ assertXPath(pXmlDoc2, sPathStart + "/draw:opacity[@draw:name='msTransGradient_20_1']");
+
+ xmlDocUniquePtr pXmlDoc3 = parseExport(tempFile2, "Object 1/content.xml");
+ sPathStart = "//office:document-content/office:automatic-styles/style:style[@style:name='ch2']";
+ assertXPath(pXmlDoc3, sPathStart + "/style:graphic-properties[@draw:opacity-name='msTransGradient_20_1']");
+ sPathStart = "//office:document-content/office:body/office:chart/chart:chart";
+ assertXPath(pXmlDoc3, sPathStart + "/chart:legend[@chart:style-name='ch2']");
+ xDocShRef->DoClose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest1);
CPPUNIT_PLUGIN_IMPLEMENT();