oox/qa/unit/data/tdf139618_ImportWordArtGradient.pptx |binary oox/qa/unit/data/tdf139618_ThemeColorTransparency.pptx |binary oox/qa/unit/data/tdf139618_WordArtBitmapFill.pptx |binary oox/qa/unit/export.cxx | 26 +++ oox/qa/unit/shape.cxx | 130 ++++++++++++++++ oox/source/drawingml/shape.cxx | 43 +++-- oox/source/drawingml/textcharacterpropertiescontext.cxx | 1 oox/source/export/drawingml.cxx | 12 + sd/qa/unit/export-tests-ooxml3.cxx | 5 9 files changed, 199 insertions(+), 18 deletions(-)
New commits: commit 260735ff98631b94ae8737cf1cead3e20bade618 Author: Regina Henschel <rb.hensc...@t-online.de> AuthorDate: Sat Mar 11 18:39:06 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Mar 14 07:40:00 2023 +0000 tdf#139618 Add WordArt fill types in pptx import This fix uses a similar approach as in WpsContext::onEndElement, only that here moTextOutlineProperties and maFillProperties are still available whereas in WpsContext the properties need to be collected from CharInteropGrabBag. I have adapted unit test testTdf125573_FontworkScaleX because now the gradient is imported, see comment in former version of the test. Change-Id: I989ee475867c97b9f93c7e65cd25483611eec7bf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148687 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/oox/qa/unit/data/tdf139618_ImportWordArtGradient.pptx b/oox/qa/unit/data/tdf139618_ImportWordArtGradient.pptx new file mode 100644 index 000000000000..8fd4bcc181f0 Binary files /dev/null and b/oox/qa/unit/data/tdf139618_ImportWordArtGradient.pptx differ diff --git a/oox/qa/unit/data/tdf139618_ThemeColorTransparency.pptx b/oox/qa/unit/data/tdf139618_ThemeColorTransparency.pptx new file mode 100644 index 000000000000..405135783e16 Binary files /dev/null and b/oox/qa/unit/data/tdf139618_ThemeColorTransparency.pptx differ diff --git a/oox/qa/unit/data/tdf139618_WordArtBitmapFill.pptx b/oox/qa/unit/data/tdf139618_WordArtBitmapFill.pptx new file mode 100644 index 000000000000..5da52ceb3c15 Binary files /dev/null and b/oox/qa/unit/data/tdf139618_WordArtBitmapFill.pptx differ diff --git a/oox/qa/unit/export.cxx b/oox/qa/unit/export.cxx index 0e2a2669ee79..a98eaa5ce93f 100644 --- a/oox/qa/unit/export.cxx +++ b/oox/qa/unit/export.cxx @@ -1297,6 +1297,32 @@ CPPUNIT_TEST_FIXTURE(Test, testFontworkRectGradient) assertXPath(pXmlDoc, sElement + "w14:gs[3]/w14:schemeClr/w14:lumOff", "val", "60000"); assertXPath(pXmlDoc, sElement + "w14:gs[3]/w14:schemeClr/w14:alpha", "val", "70000"); } + +CPPUNIT_TEST_FIXTURE(Test, testThemeColorTransparency) +{ + // The document has first a Fontwork shape with solid fill theme color with transparency and + // outline transparency and second a textbox with character transparency. + // Without fix the transparency was not written to file. + loadFromURL(u"tdf139618_ThemeColorTransparency.pptx"); + + save("Impress Office Open XML"); + xmlDocUniquePtr pXmlDoc = parseExport("ppt/slides/slide1.xml"); + + // Make sure a:alpha is written for line color and for fill color. + // Make sure fill color is a schemeClr. + OString sElement = "/p:sld/p:cSld/p:spTree/p:sp[1]/p:txBody/a:p/a:r/a:rPr/"; + assertXPath(pXmlDoc, sElement + "a:ln/a:solidFill/a:srgbClr/a:alpha", "val", "25000"); + assertXPath(pXmlDoc, sElement + "a:solidFill/a:schemeClr", "val", "accent1"); + assertXPath(pXmlDoc, sElement + "a:solidFill/a:schemeClr/a:lumMod", "val", "60000"); + assertXPath(pXmlDoc, sElement + "a:solidFill/a:schemeClr/a:lumOff", "val", "40000"); + assertXPath(pXmlDoc, sElement + "a:solidFill/a:schemeClr/a:alpha", "val", "35000"); + + // Make sure a:alpha is written for characters and fill color is a schemeClr. + sElement = "/p:sld/p:cSld/p:spTree/p:sp[2]/p:txBody/a:p/a:r/a:rPr/"; + assertXPath(pXmlDoc, sElement + "a:solidFill/a:schemeClr", "val", "accent4"); + assertXPath(pXmlDoc, sElement + "a:solidFill/a:schemeClr/a:lumMod", "val", "75000"); + assertXPath(pXmlDoc, sElement + "a:solidFill/a:schemeClr/a:alpha", "val", "20000"); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/oox/qa/unit/shape.cxx b/oox/qa/unit/shape.cxx index b5a3fe8b1113..523003ee351a 100644 --- a/oox/qa/unit/shape.cxx +++ b/oox/qa/unit/shape.cxx @@ -16,7 +16,9 @@ #include <com/sun/star/awt/FontWeight.hpp> #include <com/sun/star/awt/Gradient.hpp> #include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/awt/XBitmap.hpp> #include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/BitmapMode.hpp> #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/LineDash.hpp> #include <com/sun/star/drawing/LineJoint.hpp> @@ -24,6 +26,7 @@ #include <com/sun/star/drawing/TextHorizontalAdjust.hpp> #include <com/sun/star/drawing/TextVerticalAdjust.hpp> #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> #include <com/sun/star/lang/Locale.hpp> #include <com/sun/star/text/XTextFrame.hpp> #include <com/sun/star/text/XTextRange.hpp> @@ -585,6 +588,133 @@ CPPUNIT_TEST_FIXTURE(OoxShapeTest, testWriterFontworkDarkenTransparency) CPPUNIT_ASSERT_EQUAL(uno::Any(Color(208, 175, 114)), xShapeProps->getPropertyValue(u"FillColor")); } + +CPPUNIT_TEST_FIXTURE(OoxShapeTest, testImportWordArtGradient) +{ + loadFromURL(u"tdf139618_ImportWordArtGradient.pptx"); + // Without the patch all WordArt was imported with solid color. Now gradient is imported. + // This test covers several aspects of import of gradient fill. + + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + + // linear gradient, MSO UI 21deg, solid transparency on outline + { + uno::Reference<beans::XPropertySet> xShapeProps(xDrawPage->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::FillStyle_GRADIENT), + xShapeProps->getPropertyValue(u"FillStyle")); + awt::Gradient aGradient; + xShapeProps->getPropertyValue(u"FillGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_LINEAR, aGradient.Style); + CPPUNIT_ASSERT_EQUAL(sal_Int16(690), aGradient.Angle); + CPPUNIT_ASSERT_EQUAL(sal_Int32(16760832), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(12582912), aGradient.EndColor); + + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::LineStyle_SOLID), + xShapeProps->getPropertyValue(u"LineStyle")); + sal_Int32 nOutlineColor; + xShapeProps->getPropertyValue(u"LineColor") >>= nOutlineColor; + CPPUNIT_ASSERT_EQUAL(sal_Int32(7384391), nOutlineColor); + sal_Int16 nLineTransparence; + xShapeProps->getPropertyValue(u"LineTransparence") >>= nLineTransparence; + CPPUNIT_ASSERT_EQUAL(sal_Int16(60), nLineTransparence); + } + + // radial gradient, direct color with transparency, focus center, dotted outline + // The stop color transparency is imported as transparency gradient with same geometry. + { + uno::Reference<beans::XPropertySet> xShapeProps(xDrawPage->getByIndex(1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::FillStyle_GRADIENT), + xShapeProps->getPropertyValue(u"FillStyle")); + awt::Gradient aGradient; + xShapeProps->getPropertyValue(u"FillGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_RADIAL, aGradient.Style); + CPPUNIT_ASSERT_EQUAL(sal_Int32(15132160), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(33760), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.XOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.YOffset); + + xShapeProps->getPropertyValue(u"FillTransparenceGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_RADIAL, aGradient.Style); + // Transparency is encoded in gray color. + CPPUNIT_ASSERT_EQUAL(sal_Int32(5000268), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(6710886), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.XOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), aGradient.YOffset); + + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::LineStyle_DASH), + xShapeProps->getPropertyValue(u"LineStyle")); + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::LineCap_ROUND), + xShapeProps->getPropertyValue(u"LineCap")); + CPPUNIT_ASSERT_EQUAL(uno::Any(sal_Int32(7384391)), + xShapeProps->getPropertyValue(u"LineColor")); + drawing::LineDash aLineDash; + xShapeProps->getPropertyValue(u"LineDash") >>= aLineDash; + CPPUNIT_ASSERT_EQUAL(drawing::DashStyle_ROUNDRELATIVE, aLineDash.Style); + CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aLineDash.Dots); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aLineDash.Dashes); + } + + // solid theme color accent 1, rectangular transparency gradient, focus top-right, no outline + // FillProperties::pushToPropMap imports this currently (Mar 2023) as color gradient. + // Thus no theme color is tested but direct color. + { + uno::Reference<beans::XPropertySet> xShapeProps(xDrawPage->getByIndex(2), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::FillStyle_GRADIENT), + xShapeProps->getPropertyValue(u"FillStyle")); + awt::Gradient aGradient; + xShapeProps->getPropertyValue(u"FillGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_RECT, aGradient.Style); + CPPUNIT_ASSERT_EQUAL(sal_Int32(4485828), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(4485828), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int16(100), aGradient.XOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aGradient.YOffset); + + xShapeProps->getPropertyValue(u"FillTransparenceGradient") >>= aGradient; + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_RECT, aGradient.Style); + // Transparency is encoded in gray color. + CPPUNIT_ASSERT_EQUAL(sal_Int32(16777215), aGradient.EndColor); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aGradient.StartColor); + CPPUNIT_ASSERT_EQUAL(sal_Int16(100), aGradient.XOffset); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aGradient.YOffset); + + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::LineStyle_NONE), + xShapeProps->getPropertyValue(u"LineStyle")); + } +} + +CPPUNIT_TEST_FIXTURE(OoxShapeTest, testWordArtBitmapFill) +{ + // The document has a WordArt shape with bitmap fill. + // Without fix it was imported as solid color fill. + loadFromURL(u"tdf139618_WordArtBitmapFill.pptx"); + + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShapeProps(xDrawPage->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::FillStyle_BITMAP), + xShapeProps->getPropertyValue(u"FillStyle")); + + // Test some bitmap properties + CPPUNIT_ASSERT_EQUAL(uno::Any(drawing::BitmapMode_REPEAT), + xShapeProps->getPropertyValue(u"FillBitmapMode")); + CPPUNIT_ASSERT_EQUAL(uno::Any(true), xShapeProps->getPropertyValue(u"FillBitmapTile")); + uno::Reference<awt::XBitmap> xBitmap; + xShapeProps->getPropertyValue(u"FillBitmap") >>= xBitmap; + + uno::Reference<graphic::XGraphic> xGraphic; + xGraphic.set(xBitmap, uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xGraphicDescriptor(xGraphic, uno::UNO_QUERY_THROW); + OUString sMimeType; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("MimeType") >>= sMimeType); + CPPUNIT_ASSERT_EQUAL(OUString("image/jpeg"), sMimeType); + awt::Size aSize100thMM; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("Size100thMM") >>= aSize100thMM); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1592), aSize100thMM.Width); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1592), aSize100thMM.Height); +} CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index ccfd61410bd5..18e087dc2207 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -696,27 +696,38 @@ static void lcl_copyCharPropsToShape(const uno::Reference<drawing::XShape>& xSha xSet->setPropertyValue(u"CharFontFamilyComplex", uno::Any(nFontFamily)); } - // LO uses shape fill, MS Office character fill. Currently only this solid fill workaround - // is implemented. - // ToDo: Consider other fill styles - // ToDo: Consider Color Theme - xSet->setPropertyValue(UNO_NAME_FILLSTYLE, uno::Any(drawing::FillStyle_SOLID)); - sal_Int32 aFillColor(COL_BLACK); //default - if (rCharProps.maFillProperties.maFillColor.isUsed()) + // LO uses shape properties, MS Office character properties. Copy them from char to shape. + // Outline + if (rCharProps.moTextOutlineProperties.has_value()) { - aFillColor = static_cast<sal_Int32>( - rCharProps.maFillProperties.maFillColor.getColor(rFilter.getGraphicHelper()) - .GetRGBColor()); - if (rCharProps.maFillProperties.maFillColor.hasTransparency()) + oox::drawingml::ShapePropertyMap aStrokeShapeProps(rFilter.getModelObjectHelper()); + rCharProps.moTextOutlineProperties.value().pushToPropMap( + aStrokeShapeProps, rFilter.getGraphicHelper()); + for (const auto& rProp : aStrokeShapeProps.makePropertyValueSequence()) { - const sal_Int16 aTransparence - = rCharProps.maFillProperties.maFillColor.getTransparency(); - xSet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, uno::Any(aTransparence)); + xSet->setPropertyValue(rProp.Name, rProp.Value); } } - xSet->setPropertyValue(UNO_NAME_FILLCOLOR, uno::Any(aFillColor)); + else + { + xSet->setPropertyValue(UNO_NAME_LINESTYLE, uno::Any(drawing::LineStyle_NONE)); + } + + // Fill + // ToDo: Replace flip and rotate constants in parameters with actual values. + oox::drawingml::ShapePropertyMap aFillShapeProps(rFilter.getModelObjectHelper()); + rCharProps.maFillProperties.pushToPropMap(aFillShapeProps, rFilter.getGraphicHelper(), + /*nShapeRotation*/ 0, + /*nPhClr*/ API_RGB_TRANSPARENT, + /*nPhClrTheme*/ -1, + /*bFlipH*/ false, /*bFlipV*/ false, + /*bIsCustomShape*/ true); + for (const auto& rProp : aFillShapeProps.makePropertyValueSequence()) + { + xSet->setPropertyValue(rProp.Name, rProp.Value); + } - // ToDo: copy character outline to shape stroke. + // ToDo: Import WordArt glow and simple shadow effects. They are available in LO. } // LO does not evaluate paragraph alignment in text path mode. Use text area anchor instead. diff --git a/oox/source/drawingml/textcharacterpropertiescontext.cxx b/oox/source/drawingml/textcharacterpropertiescontext.cxx index c5cf346de199..2b87aa7f1cd0 100644 --- a/oox/source/drawingml/textcharacterpropertiescontext.cxx +++ b/oox/source/drawingml/textcharacterpropertiescontext.cxx @@ -123,6 +123,7 @@ ContextHandlerRef TextCharacterPropertiesContext::onCreateContext( sal_Int32 aEl case A_TOKEN( solidFill ): case A_TOKEN( gradFill ): case A_TOKEN( pattFill ): + case A_TOKEN( blipFill ): // Fontwork uses blibFill. return FillPropertiesContext::createFillContext( *this, aElementToken, rAttribs, mrTextCharacterProperties.maFillProperties ); // EG_EffectProperties case A_TOKEN( effectDag ): // CT_EffectContainer 5.1.10.25 diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 5f2e1a7b4558..8f16b1ebc95e 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -582,6 +582,18 @@ bool DrawingML::WriteSchemeColor(OUString const& rPropertyName, const uno::Refer break; } } + // Alpha is actually not contained in maTransformations although possible (as of Mar 2023). + sal_Int16 nAPITransparency(0); + if ((rPropertyName == u"FillColorThemeReference" + && GetProperty(xPropertySet, "FillTransparence")) + || (rPropertyName == u"LineColorThemeReference" + && GetProperty(xPropertySet, "LineTransparence")) + || (rPropertyName == u"CharColorThemeReference" + && GetProperty(xPropertySet, "CharTransparence"))) + mAny >>= nAPITransparency; + if (nAPITransparency != 0) + mpFS->singleElementNS(XML_a, XML_alpha, XML_val, + OString::number(MAX_PERCENT - (PER_PERCENT * nAPITransparency))); mpFS->endElementNS(XML_a, XML_schemeClr); mpFS->endElementNS(XML_a, XML_solidFill); diff --git a/sd/qa/unit/export-tests-ooxml3.cxx b/sd/qa/unit/export-tests-ooxml3.cxx index 405170ffcdcf..3bec0e59d348 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -575,20 +575,21 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest3, testTdf125573_FontWorkScaleX) assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp[1]/p:txBody/a:bodyPr[@fromWordArt='1']"); - // State of Nov 2022. It needs to be updated, when import of fill and stroke is implemented. // Error was, that text in legacy shapes of category "Follow Path" was not scaled to the path. uno::Reference<beans::XPropertySet> xShapeArchProps(getShapeFromPage(0, 0)); awt::Rectangle aBoundRectArch; xShapeArchProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectArch; // BoundRect is DPI dependent, thus allow some range. + // Expected width is 13139 in 96dpi and is 13106 in 120 dpi, for example // (Without fix Expected less than: 85 Actual : 10432) - CPPUNIT_ASSERT_LESS(sal_Int32(85), std::abs(aBoundRectArch.Width - 13038)); + CPPUNIT_ASSERT_LESS(sal_Int32(85), std::abs(aBoundRectArch.Width - 13139)); // Error was, that text in shapes of category "Warp" was not scaled to the path. uno::Reference<beans::XPropertySet> xShapeWaveProps(getShapeFromPage(0, 1)); awt::Rectangle aBoundRectWave; xShapeWaveProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectWave; // BoundRect is DPI dependent, thus allow some range. + // Expected with is 11576 in 96dpt and is 11578 in 120dpi, for example CPPUNIT_ASSERT_LESS(sal_Int32(85), std::abs(aBoundRectWave.Width - 11576)); }