diff options
-rw-r--r-- | include/oox/export/chartexport.hxx | 1 | ||||
-rw-r--r-- | oox/source/drawingml/chart/objectformatter.cxx | 2 | ||||
-rw-r--r-- | oox/source/export/chartexport.cxx | 103 | ||||
-rw-r--r-- | sd/qa/unit/data/odp/tdf128345_ChartArea_CG_TS.odp | bin | 0 -> 19486 bytes | |||
-rw-r--r-- | sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odp | bin | 0 -> 16551 bytes | |||
-rw-r--r-- | sd/qa/unit/data/odp/tdf128345_Legend_CS_TG_axial.odp | bin | 0 -> 15174 bytes | |||
-rw-r--r-- | sd/qa/unit/export-tests-ooxml1.cxx | 120 |
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 Binary files differnew file mode 100644 index 000000000000..754e71d51222 --- /dev/null +++ b/sd/qa/unit/data/odp/tdf128345_ChartArea_CG_TS.odp diff --git a/sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odp b/sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odp Binary files differnew file mode 100644 index 000000000000..4c09ebb7bb34 --- /dev/null +++ b/sd/qa/unit/data/odp/tdf128345_Chart_CS_TG.odp 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 Binary files differnew file mode 100644 index 000000000000..bfcd8a5dd5c9 --- /dev/null +++ b/sd/qa/unit/data/odp/tdf128345_Legend_CS_TG_axial.odp 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(); |