drawinglayer/source/tools/emfpbrush.cxx | 12 ++ drawinglayer/source/tools/emfphelperdata.cxx | 55 ++-------- drawinglayer/source/tools/primitive2dxmldump.cxx | 42 ++++++- emfio/qa/cppunit/emf/EmfImportTest.cxx | 24 ++++ emfio/qa/cppunit/emf/data/TestEmfPlusBrushPathGradientWithBlendColors.emf |binary svgio/qa/cppunit/SvgImportTest.cxx | 14 ++ 6 files changed, 99 insertions(+), 48 deletions(-)
New commits: commit 8419e2909aef8916111e4dce9c0a070464a06e66 Author: Bartosz Kosiorek <gan...@poczta.onet.pl> AuthorDate: Sun Jun 12 21:51:52 2022 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Wed Jun 15 08:41:31 2022 +0200 tdf#131506 tdf#143031 EMF+ Fix displaying PathGradient fill With previous implementation, the EMF+ import is calculating gradient positions wrongly. It is causing warning: SvgGradientHelper got invalid SvgGradientEntries outside [0.0 .. 1.0] and the gradient was not displayed at all. This patch fixes that and gradient is displayed correctly Change-Id: I6229c516165436d0c7ae187d9eb69b5494da396f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135607 Tested-by: Jenkins Reviewed-by: Bartosz Kosiorek <gan...@poczta.onet.pl> (cherry picked from commit 7b12c659842eb53b96dd98ecea65c6071506dfbb) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135746 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135858 diff --git a/drawinglayer/source/tools/emfpbrush.cxx b/drawinglayer/source/tools/emfpbrush.cxx index 4acc311345a8..493b6eafc613 100644 --- a/drawinglayer/source/tools/emfpbrush.cxx +++ b/drawinglayer/source/tools/emfpbrush.cxx @@ -187,6 +187,12 @@ namespace emfplushelper SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse brush transformation: " << brush_transformation); } + // BrushDataPresetColors and BrushDataBlendFactorsH + if ((additionalFlags & 0x04) && (additionalFlags & 0x08)) + { + SAL_WARN("drawinglayer.emf", "EMF+\t Brush must not contain both BrushDataPresetColors and BrushDataBlendFactorsH"); + return; + } if (additionalFlags & 0x08) { s.ReadInt32(blendPoints); @@ -268,6 +274,12 @@ namespace emfplushelper hasTransformation = true; SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse brush transformation: " << brush_transformation); } + // BrushDataPresetColors and BrushDataBlendFactorsH + if ((additionalFlags & 0x04) && (additionalFlags & 0x08)) + { + SAL_WARN("drawinglayer.emf", "EMF+\t Brush must not contain both BrushDataPresetColors and BrushDataBlendFactorsH"); + return; + } if (additionalFlags & 0x08) { diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx index 7a64f8ad4dac..df3c4293a87f 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -784,21 +784,12 @@ namespace emfplushelper // store the blendpoints in the vector for (int i = 0; i < brush->blendPoints; i++) { - double aBlendPoint; + const double aBlendPoint = brush->blendPositions[i]; basegfx::BColor aColor; - if (brush->type == BrushTypeLinearGradient) - { - aBlendPoint = brush->blendPositions [i]; - } - else - { - // seems like SvgRadialGradientPrimitive2D needs doubled, inverted radius - aBlendPoint = 2. * ( 1. - brush->blendPositions [i] ); - } - aColor.setGreen( aStartColor.getGreen() + brush->blendFactors[i] * ( aEndColor.getGreen() - aStartColor.getGreen() ) ); - aColor.setBlue ( aStartColor.getBlue() + brush->blendFactors[i] * ( aEndColor.getBlue() - aStartColor.getBlue() ) ); - aColor.setRed ( aStartColor.getRed() + brush->blendFactors[i] * ( aEndColor.getRed() - aStartColor.getRed() ) ); - const double aAlpha = brush->solidColor.GetAlpha() + brush->blendFactors[i] * ( brush->secondColor.GetAlpha() - brush->solidColor.GetAlpha() ); + aColor.setGreen(aStartColor.getGreen() + brush->blendFactors[i] * (aEndColor.getGreen() - aStartColor.getGreen())); + aColor.setBlue (aStartColor.getBlue() + brush->blendFactors[i] * (aEndColor.getBlue() - aStartColor.getBlue())); + aColor.setRed (aStartColor.getRed() + brush->blendFactors[i] * (aEndColor.getRed() - aStartColor.getRed())); + const double aAlpha = brush->solidColor.GetAlpha() + brush->blendFactors[i] * (brush->secondColor.GetAlpha() - brush->solidColor.GetAlpha()); aVector.emplace_back(aBlendPoint, aColor, aAlpha / 255.0); } } @@ -809,33 +800,15 @@ namespace emfplushelper // store the colorBlends in the vector for (int i = 0; i < brush->colorblendPoints; i++) { - double aBlendPoint; - basegfx::BColor aColor; - if (brush->type == BrushTypeLinearGradient) - { - aBlendPoint = brush->colorblendPositions [i]; - } - else - { - // seems like SvgRadialGradientPrimitive2D needs doubled, inverted radius - aBlendPoint = 2. * ( 1. - brush->colorblendPositions [i] ); - } - aColor = brush->colorblendColors[i].getBColor(); - aVector.emplace_back(aBlendPoint, aColor, brush->colorblendColors[i].GetAlpha() / 255.0 ); + const double aBlendPoint = brush->colorblendPositions[i]; + const basegfx::BColor aColor = brush->colorblendColors[i].getBColor(); + aVector.emplace_back(aBlendPoint, aColor, brush->colorblendColors[i].GetAlpha() / 255.0); } } else // ok, no extra points: just start and end { - if (brush->type == BrushTypeLinearGradient) - { - aVector.emplace_back(0.0, aStartColor, brush->solidColor.GetAlpha() / 255.0); - aVector.emplace_back(1.0, aEndColor, brush->secondColor.GetAlpha() / 255.0); - } - else // again, here reverse - { - aVector.emplace_back(0.0, aEndColor, brush->secondColor.GetAlpha() / 255.0); - aVector.emplace_back(1.0, aStartColor, brush->solidColor.GetAlpha() / 255.0); - } + aVector.emplace_back(0.0, aStartColor, brush->solidColor.GetAlpha() / 255.0); + aVector.emplace_back(1.0, aEndColor, brush->secondColor.GetAlpha() / 255.0); } // get the polygon range to be able to map the start/end/center point correctly @@ -886,7 +859,7 @@ namespace emfplushelper aSpreadMethod)); } else // BrushTypePathGradient - { + { // TODO The PathGradient is not implemented, and Radial Gradient is used instead basegfx::B2DPoint aCenterPoint = Map(brush->firstPointX, brush->firstPointY); aCenterPoint = aPolygonTransformation * aCenterPoint; @@ -897,9 +870,9 @@ namespace emfplushelper polygon, std::move(aVector), aCenterPoint, - 0.5, // relative radius - true, // use UnitCoordinates to stretch the gradient - drawinglayer::primitive2d::SpreadMethod::Repeat, + 0.7, // relative radius little bigger to cover all elements + true, // use UnitCoordinates to stretch the gradient + drawinglayer::primitive2d::SpreadMethod::Pad, nullptr)); } } diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx b/drawinglayer/source/tools/primitive2dxmldump.cxx index 27a8adf1b5e3..fcad3a03bbac 100644 --- a/drawinglayer/source/tools/primitive2dxmldump.cxx +++ b/drawinglayer/source/tools/primitive2dxmldump.cxx @@ -458,6 +458,25 @@ void writeMaterialAttribute(::tools::XmlWriter& rWriter, rWriter.endElement(); } +void writeSpreadMethod(::tools::XmlWriter& rWriter, + const drawinglayer::primitive2d::SpreadMethod& rSpreadMethod) +{ + switch (rSpreadMethod) + { + case drawinglayer::primitive2d::SpreadMethod::Pad: + rWriter.attribute("spreadmethod", "pad"); + break; + case drawinglayer::primitive2d::SpreadMethod::Reflect: + rWriter.attribute("spreadmethod", "reflect"); + break; + case drawinglayer::primitive2d::SpreadMethod::Repeat: + rWriter.attribute("spreadmethod", "repeat"); + break; + default: + rWriter.attribute("spreadmethod", "unknown"); + } +} + } // end anonymous namespace Primitive2dXmlDump::Primitive2dXmlDump() @@ -887,13 +906,28 @@ void Primitive2dXmlDump::decomposeAndWrite( const SvgRadialGradientPrimitive2D& rSvgRadialGradientPrimitive2D = dynamic_cast<const SvgRadialGradientPrimitive2D&>(*pBasePrimitive); rWriter.startElement("svgradialgradient"); - basegfx::B2DPoint aFocusAttribute = rSvgRadialGradientPrimitive2D.getFocal(); + if (rSvgRadialGradientPrimitive2D.isFocalSet()) + { + basegfx::B2DPoint aFocalAttribute = rSvgRadialGradientPrimitive2D.getFocal(); + rWriter.attribute("focalx", aFocalAttribute.getX()); + rWriter.attribute("focaly", aFocalAttribute.getY()); + } + basegfx::B2DPoint aStartPoint = rSvgRadialGradientPrimitive2D.getStart(); + rWriter.attribute("startx", aStartPoint.getX()); + rWriter.attribute("starty", aStartPoint.getY()); rWriter.attribute("radius", OString::number(rSvgRadialGradientPrimitive2D.getRadius())); - rWriter.attribute("focusx", aFocusAttribute.getX()); - rWriter.attribute("focusy", aFocusAttribute.getY()); + writeSpreadMethod(rWriter, rSvgRadialGradientPrimitive2D.getSpreadMethod()); + rWriter.attributeDouble( + "opacity", + rSvgRadialGradientPrimitive2D.getGradientEntries().front().getOpacity()); + + rWriter.startElement("transform"); + writeMatrix(rWriter, rSvgRadialGradientPrimitive2D.getGradientTransform()); + rWriter.endElement(); + writePolyPolygon(rWriter, rSvgRadialGradientPrimitive2D.getPolyPolygon()); rWriter.endElement(); } break; @@ -910,7 +944,7 @@ void Primitive2dXmlDump::decomposeAndWrite( rWriter.attribute("starty", aStartAttribute.getY()); rWriter.attribute("endx", aEndAttribute.getX()); rWriter.attribute("endy", aEndAttribute.getY()); - //rWriter.attribute("spreadmethod", (int)rSvgLinearGradientPrimitive2D.getSpreadMethod()); + writeSpreadMethod(rWriter, rSvgLinearGradientPrimitive2D.getSpreadMethod()); rWriter.attributeDouble( "opacity", rSvgLinearGradientPrimitive2D.getGradientEntries().front().getOpacity()); diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index a734010e0dac..112ea0926596 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -65,6 +65,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest: void TestSetArcDirection(); void TestDrawPolyLine16WithClip(); void TestFillRegion(); + void TestEmfPlusBrushPathGradientWithBlendColors(); void TestExtTextOutOpaqueAndClipTransform(); void TestBitBltStretchBltWMF(); @@ -109,6 +110,7 @@ public: CPPUNIT_TEST(TestSetArcDirection); CPPUNIT_TEST(TestDrawPolyLine16WithClip); CPPUNIT_TEST(TestFillRegion); + CPPUNIT_TEST(TestEmfPlusBrushPathGradientWithBlendColors); CPPUNIT_TEST(TestExtTextOutOpaqueAndClipTransform); CPPUNIT_TEST(TestBitBltStretchBltWMF); @@ -452,6 +454,7 @@ void Test::TestLinearGradient() assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "width", "15232"); assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "path", "m0 0h15232v7610h-15232z"); + assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[1]", "spreadmethod", "repeat"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[1]", "startx", "0"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[1]", "starty", "-1"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[1]", "endx", "0"); @@ -460,6 +463,8 @@ void Test::TestLinearGradient() "0.392156862745098"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[1]/polypolygon", "path", "m0 0.216110019646294h7615.75822989746v7610.21611001965h-7615.75822989746z"); + + assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]", "spreadmethod", "repeat"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]", "startx", "-1"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]", "starty", "-1"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]", "endx", "0"); @@ -890,6 +895,25 @@ void Test::TestPolylinetoCloseStroke() assertXPath(pDocument, aXPathPrefix + "polygonhairline[2]", "color", "#000000"); } +void Test::TestEmfPlusBrushPathGradientWithBlendColors() +{ + // tdf#131506 EMF+ records: FillRects, Brush with PathGradient and BlendColor, FillRects + Primitive2DSequence aSequence + = parseEmf(u"emfio/qa/cppunit/emf/data/TestEmfPlusBrushPathGradientWithBlendColors.emf"); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength())); + drawinglayer::Primitive2dXmlDump dumper; + xmlDocUniquePtr pDocument + = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence)); + CPPUNIT_ASSERT(pDocument); + + assertXPath(pDocument, aXPathPrefix + "svgradialgradient", "radius", "0.7"); + assertXPath(pDocument, aXPathPrefix + "svgradialgradient/focalx", 0); + assertXPath(pDocument, aXPathPrefix + "svgradialgradient/focaly", 0); + assertXPath(pDocument, aXPathPrefix + "svgradialgradient", "startx", "0"); + assertXPath(pDocument, aXPathPrefix + "svgradialgradient", "starty", "0"); + assertXPath(pDocument, aXPathPrefix + "svgradialgradient", "spreadmethod", "pad"); +} + void Test::TestExtTextOutOpaqueAndClipTransform() { // tdf#142495 EMF records: SETBKCOLOR, SELECTOBJECT, EXTTEXTOUTW, MODIFYWORLDTRANSFORM, CREATEFONTINDIRECT. diff --git a/emfio/qa/cppunit/emf/data/TestEmfPlusBrushPathGradientWithBlendColors.emf b/emfio/qa/cppunit/emf/data/TestEmfPlusBrushPathGradientWithBlendColors.emf new file mode 100644 index 000000000000..caa9876bd449 Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestEmfPlusBrushPathGradientWithBlendColors.emf differ diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx index 3034c997015e..c563e7b296fd 100644 --- a/svgio/qa/cppunit/SvgImportTest.cxx +++ b/svgio/qa/cppunit/SvgImportTest.cxx @@ -412,9 +412,13 @@ void Test::testTdf97542_2() CPPUNIT_ASSERT (pDocument); - assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient[1]", "focusx", "1"); - assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient[1]", "focusy", "1"); - assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient[1]", "radius", "3"); + assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient", "startx", "1"); + assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient", "starty", "1"); + assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient/focalx", 0); + assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient/focaly", 0); + assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient", "radius", "3"); + assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient", "spreadmethod", "pad"); + assertXPath(pDocument, "/primitive2D/transform/objectinfo/svgradialgradient", "opacity", "1"); } void Test::testTdf97543() @@ -738,8 +742,12 @@ void Test::testTdf94765() CPPUNIT_ASSERT (pDocument); //Check that both rectangles use the gradient as fill + assertXPath(pDocument, "/primitive2D/transform/transform/svglineargradient[1]", "startx", "1"); + assertXPath(pDocument, "/primitive2D/transform/transform/svglineargradient[1]", "starty", "1"); assertXPath(pDocument, "/primitive2D/transform/transform/svglineargradient[1]", "endx", "2"); assertXPath(pDocument, "/primitive2D/transform/transform/svglineargradient[1]", "endy", "1"); + assertXPath(pDocument, "/primitive2D/transform/transform/svglineargradient[2]", "startx", "0"); + assertXPath(pDocument, "/primitive2D/transform/transform/svglineargradient[2]", "starty", "0"); assertXPath(pDocument, "/primitive2D/transform/transform/svglineargradient[2]", "endx", "0"); assertXPath(pDocument, "/primitive2D/transform/transform/svglineargradient[2]", "endy", "0"); }