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");
 }

Reply via email to