emfio/inc/mtftools.hxx                            |    4 +
 emfio/qa/cppunit/emf/EmfImportTest.cxx            |   48 ++++++++++++++++++++++
 emfio/qa/cppunit/emf/data/TestSetArcDirection.emf |binary
 emfio/source/reader/emfreader.cxx                 |   16 +++++--
 emfio/source/reader/mtftools.cxx                  |    9 ++++
 include/tools/poly.hxx                            |    3 -
 tools/inc/poly.h                                  |    2 
 tools/source/generic/poly.cxx                     |   41 ++++++++++++------
 8 files changed, 104 insertions(+), 19 deletions(-)

New commits:
commit 7b28920382d3820344bfc4075bac98f85e838dba
Author:     Bartosz Kosiorek <gan...@poczta.onet.pl>
AuthorDate: Mon Mar 7 12:26:03 2022 +0100
Commit:     Bartosz Kosiorek <gan...@poczta.onet.pl>
CommitDate: Thu Mar 10 21:19:59 2022 +0100

    tdf#113066 tdf#142204 EMF Implement SETARCDIRECTION
    
    Change-Id: I30206c68ecf1829ba0094e6259b8ed7dc05f2e9a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131103
    Tested-by: Jenkins
    Reviewed-by: Bartosz Kosiorek <gan...@poczta.onet.pl>

diff --git a/emfio/inc/mtftools.hxx b/emfio/inc/mtftools.hxx
index 84a012f183d6..d258a9250b91 100644
--- a/emfio/inc/mtftools.hxx
+++ b/emfio/inc/mtftools.hxx
@@ -454,6 +454,7 @@ namespace emfio
         WinMtfClipPath      maClipPath;
         XForm               aXForm;
 
+        bool                bClockWiseArcDirection;
         bool                bFillStyleSelected;
     };
 
@@ -565,6 +566,7 @@ namespace emfio
         ScaledFontDetectCorrectHelper maScaledFontHelper;
 
         bool                mbNopMode : 1;
+        bool                mbClockWiseArcDirection : 1;
         bool                mbFillStyleSelected : 1;
         bool                mbClipNeedsUpdate : 1;
         bool                mbComplexClip : 1;
@@ -618,6 +620,8 @@ namespace emfio
 
         void                SetGfxMode(sal_Int32 nGfxMode) { mnGfxMode = 
nGfxMode; };
         sal_Int32           GetGfxMode() const { return mnGfxMode; };
+        void                SetArcDirection(bool bCounterClockWise);
+        bool                IsArcDirectionClockWise() { return 
mbClockWiseArcDirection; };
         void                SetBkMode(BkMode nMode);
         void                SetBkColor(const Color& rColor);
         void                SetTextColor(const Color& rColor);
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx 
b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index c9c2bcb94219..fce8961a849a 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -60,6 +60,7 @@ class Test : public test::BootstrapFixture, public 
XmlTestTools, public unotest:
     void TestChordWithModifyWorldTransform();
     void TestEllipseWithSelectClipPath();
     void TestEllipseXformIntersectClipRect();
+    void TestSetArcDirection();
     void TestDrawPolyLine16WithClip();
     void TestFillRegion();
     void TestExtTextOutOpaqueAndClipTransform();
@@ -102,6 +103,7 @@ public:
     CPPUNIT_TEST(TestChordWithModifyWorldTransform);
     CPPUNIT_TEST(TestEllipseWithSelectClipPath);
     CPPUNIT_TEST(TestEllipseXformIntersectClipRect);
+    CPPUNIT_TEST(TestSetArcDirection);
     CPPUNIT_TEST(TestDrawPolyLine16WithClip);
     CPPUNIT_TEST(TestFillRegion);
     CPPUNIT_TEST(TestExtTextOutOpaqueAndClipTransform);
@@ -700,6 +702,52 @@ void Test::TestEllipseXformIntersectClipRect()
         "3625,320 3625,320");
 }
 
+void Test::TestSetArcDirection()
+{
+    // EMF import test with records: SETARCDIRECTION, ARC, PIE
+    Primitive2DSequence aSequence = 
parseEmf(u"/emfio/qa/cppunit/emf/data/TestSetArcDirection.emf");
+    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
+    drawinglayer::Primitive2dXmlDump dumper;
+    xmlDocUniquePtr pDocument = 
dumper.dumpAndParse(Primitive2DContainer(aSequence));
+    CPPUNIT_ASSERT(pDocument);
+
+    assertXPath(pDocument, aXPathPrefix + "polypolygoncolor", "color", 
"#ffffff");
+    assertXPath(
+        pDocument, aXPathPrefix + "polypolygoncolor/polypolygon", "path",
+        "m1640 1570-1000-950 50-50 50-50 50-50 50-40 60-40 50-40 60-30 60-40 
60-20 60-30 70-20 "
+        "60-20 70-10 60-20h70l70-10h60 70l70 10 60 10 70 10 70 20 60 20 60 20 
70 30 60 30 60 30 50 "
+        "40 60 40 50 40 50 40 50 50 50 50 50 50 40 60 40 60 40 60 30 60 30 60 
30 60 20 70 30 70 10 "
+        "60 20 70 10 70 10 70 10 70v80 70l-10 70v70l-10 70-20 70-20 70z");
+    assertXPath(pDocument, aXPathPrefix + "polygonhairline", 2);
+    assertXPath(pDocument, aXPathPrefix + "polygonhairline[1]", "color", 
"#000000");
+    assertXPath(pDocument, aXPathPrefix + "polygonhairline[2]", "color", 
"#000000");
+    assertXPath(pDocument, aXPathPrefix + "polygonhairline", 2);
+    assertXPathContent(
+        pDocument, aXPathPrefix + "polygonhairline[1]/polygon",
+        "1070,1570 1110,1560 1160,1540 1200,1530 1250,1520 1300,1510 1350,1510 
1400,1500 1440,1500 "
+        "1490,1500 1540,1500 1590,1500 1640,1510 1690,1510 1740,1520 1780,1530 
1830,1540 1880,1560 "
+        "1920,1570 1960,1590 2010,1610 2050,1630 2090,1650 2130,1670 2160,1700 
2200,1720 2230,1750 "
+        "2260,1780 2290,1810 2320,1840 2350,1870 2370,1900 2390,1930 2410,1970 
2430,2000 2440,2030 "
+        "2450,2070 2460,2110 2470,2140 2480,2180 2480,2220 2480,2250 2480,2290 
2470,2320 2470,2360 "
+        "2460,2400 2450,2430 2430,2470 2420,2500 2400,2540 2380,2570 2350,2600 
2330,2630 2300,2660 "
+        "2270,2690 2240,2720 2210,2750 2170,2770 2140,2800 2100,2820 2060,2840 
2020,2860 1980,2880 "
+        "1940,2900 1890,2920 1850,2930 1800,2940 1750,2950 1700,2960 1660,2970 
1610,2970 1560,2980 "
+        "1510,2980 1460,2980 1410,2980 1360,2970 1320,2970 1270,2960 1220,2950 
1170,2940 1130,2930 "
+        "1080,2910 1040,2900 1000,2880 950,2860 910,2840 870,2820 840,2800 
800,2770 770,2740 "
+        "730,2720 700,2690 670,2660 650,2630 620,2600 600,2560 580,2530 
560,2500 550,2460 530,2430 "
+        "520,2390 510,2360 510,2320 500,2280 500,2250 500,2210 500,2170 
510,2140 520,2100 530,2070 "
+        "540,2030 560,1990 570,1960 590,1930 610,1890 640,1860 660,1830 
690,1800 720,1770 750,1740 "
+        "790,1720 820,1690 860,1670 900,1650 940,1630 980,1610 1020,1590");
+    assertXPathContent(
+        pDocument, aXPathPrefix + "polygonhairline[2]/polygon",
+        "1640,1570 640,620 690,570 740,520 790,470 840,430 900,390 950,350 
1010,320 1070,280 "
+        "1130,260 1190,230 1260,210 1320,190 1390,180 1450,160 1520,160 
1590,150 1650,150 1720,150 "
+        "1790,160 1850,170 1920,180 1990,200 2050,220 2110,240 2180,270 
2240,300 2300,330 2350,370 "
+        "2410,410 2460,450 2510,490 2560,540 2610,590 2660,640 2700,700 
2740,760 2780,820 2810,880 "
+        "2840,940 2870,1000 2890,1070 2920,1140 2930,1200 2950,1270 2960,1340 
2970,1410 2980,1480 "
+        "2980,1560 2980,1630 2970,1700 2970,1770 2960,1840 2940,1910 
2920,1980");
+}
+
 void Test::TestDrawPolyLine16WithClip()
 {
     // EMF image with records:
diff --git a/emfio/qa/cppunit/emf/data/TestSetArcDirection.emf 
b/emfio/qa/cppunit/emf/data/TestSetArcDirection.emf
new file mode 100644
index 000000000000..589d12dc83ef
Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestSetArcDirection.emf 
differ
diff --git a/emfio/source/reader/emfreader.cxx 
b/emfio/source/reader/emfreader.cxx
index a75c0a49e57f..f34250f0ba19 100644
--- a/emfio/source/reader/emfreader.cxx
+++ b/emfio/source/reader/emfreader.cxx
@@ -168,6 +168,9 @@
 
 #define PDF_SIGNATURE 0x50444620 // "PDF "
 
+/* [MS-EMF] - v20210625 - page 28 */
+constexpr sal_Int32 ARCDIRECTION_CLOCKWISE = 0x00000002;
+
 namespace
 {
 
@@ -1060,6 +1063,13 @@ namespace emfio
                     }
                     break;
 
+                    case EMR_SETARCDIRECTION:
+                    {
+                        mpInputStream->ReadUInt32(nIndex);
+                        SetArcDirection(nIndex == ARCDIRECTION_CLOCKWISE);
+                    }
+                    break;
+
                     case EMR_SETBKCOLOR :
                     {
                         SetBkColor( ReadColor() );
@@ -1391,7 +1401,8 @@ namespace emfio
                         else
                         {
                             SAL_INFO( "emfio", "\t\t Bounds: " << nX32 << ":" 
<< nY32 << ", " << nx32 << ":" << ny32 << ", Start: " << nStartX << ":" << 
nStartY << ", End: " << nEndX << ":" << nEndY );
-                            tools::Polygon aPoly( ReadRectangle( nX32, nY32, 
nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ), PolyStyle::Arc 
);
+                            tools::Polygon aPoly(ReadRectangle(nX32, nY32, 
nx32, ny32), Point(nStartX, nStartY), Point(nEndX, nEndY), PolyStyle::Arc, 
IsArcDirectionClockWise());
+
                             if ( nRecType == EMR_CHORD )
                                 DrawPolygon( aPoly, mbRecordPath );
                             else
@@ -1408,7 +1419,7 @@ namespace emfio
                             bStatus = false;
                         else
                         {
-                            tools::Polygon aPoly( ReadRectangle( nX32, nY32, 
nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ), PolyStyle::Pie 
);
+                            tools::Polygon aPoly(ReadRectangle(nX32, nY32, 
nx32, ny32), Point(nStartX, nStartY), Point(nEndX, nEndY), PolyStyle::Pie, 
IsArcDirectionClockWise());
                             DrawPolygon( aPoly, mbRecordPath );
                         }
                     }
@@ -2162,7 +2173,6 @@ namespace emfio
                     case EMR_FLATTENPATH :
                     case EMR_WIDENPATH :
                     case EMR_POLYDRAW :
-                    case EMR_SETARCDIRECTION :
                     case EMR_SETPALETTEENTRIES :
                     case EMR_RESIZEPALETTE :
                     case EMR_EXTFLOODFILL :
diff --git a/emfio/source/reader/mtftools.cxx b/emfio/source/reader/mtftools.cxx
index e12c98c66372..f822915a2fc0 100644
--- a/emfio/source/reader/mtftools.cxx
+++ b/emfio/source/reader/mtftools.cxx
@@ -859,6 +859,12 @@ namespace emfio
         mnTextLayoutMode = nTextLayoutMode;
     }
 
+    void MtfTools::SetArcDirection(bool bClockWise)
+    {
+        SAL_INFO("emfio", "\t\t Arc direction: " << (bClockWise ? "ClockWise" 
: "CounterClockWise"));
+        mbClockWiseArcDirection = bClockWise;
+    }
+
     void MtfTools::SetBkMode( BkMode nMode )
     {
         mnBkMode = nMode;
@@ -1084,6 +1090,7 @@ namespace emfio
         mnStartPos(0),
         mnEndPos(0),
         mbNopMode(false),
+        mbClockWiseArcDirection(false),
         mbFillStyleSelected(false),
         mbClipNeedsUpdate(true),
         mbComplexClip(false),
@@ -2363,6 +2370,7 @@ namespace emfio
         pSave->nGfxMode = mnGfxMode;
         pSave->nBkMode = mnBkMode;
         pSave->aBkColor = maBkColor;
+        pSave->bClockWiseArcDirection = mbClockWiseArcDirection;
         pSave->bFillStyleSelected = mbFillStyleSelected;
 
         pSave->aActPos = maActPos;
@@ -2424,6 +2432,7 @@ namespace emfio
         mnGfxMode = pSave->nGfxMode;
         mnMapMode = pSave->nMapMode;
         maBkColor = pSave->aBkColor;
+        mbClockWiseArcDirection = pSave->bClockWiseArcDirection;
         mbFillStyleSelected = pSave->bFillStyleSelected;
 
         maActPos = pSave->aActPos;
diff --git a/include/tools/poly.hxx b/include/tools/poly.hxx
index d2ecf644af39..d9f2a4544901 100644
--- a/include/tools/poly.hxx
+++ b/include/tools/poly.hxx
@@ -93,7 +93,8 @@ public:
                                  tools::Long nRadX, tools::Long nRadY );
                         Polygon( const tools::Rectangle& rBound,
                                  const Point& rStart, const Point& rEnd,
-                                 PolyStyle ePolyStyle = PolyStyle::Arc );
+                                 PolyStyle ePolyStyle = PolyStyle::Arc,
+                                 const bool bClockWiseArcDirection = false);
                         Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
                                  const Point& rBezPt2, const Point& rCtrlPt2,
                                  sal_uInt16 nPoints );
diff --git a/tools/inc/poly.h b/tools/inc/poly.h
index 64885ac29762..772e854e31fb 100644
--- a/tools/inc/poly.h
+++ b/tools/inc/poly.h
@@ -38,7 +38,7 @@ public:
                     ImplPolygon( const tools::Rectangle& rRect, sal_uInt32 
nHorzRound, sal_uInt32 nVertRound);
                     ImplPolygon( const Point& rCenter, tools::Long nRadX, 
tools::Long nRadY );
                     ImplPolygon( const tools::Rectangle& rBound, const Point& 
rStart, const Point& rEnd,
-                                    PolyStyle eStyle );
+                                    PolyStyle eStyle, bool 
bClockWiseArcDirection );
                     ImplPolygon( const Point& rBezPt1, const Point& rCtrlPt1, 
const Point& rBezPt2,
                                     const Point& rCtrlPt2, sal_uInt16 nPoints 
);
                     ImplPolygon(const basegfx::B2DPolygon& rPolygon);
diff --git a/tools/source/generic/poly.cxx b/tools/source/generic/poly.cxx
index 6e5b2d778fa7..ed0086a9df37 100644
--- a/tools/source/generic/poly.cxx
+++ b/tools/source/generic/poly.cxx
@@ -225,21 +225,21 @@ ImplPolygon::ImplPolygon( const Point& rCenter, 
tools::Long nRadX, tools::Long n
         mnPoints = 0;
 }
 
-ImplPolygon::ImplPolygon( const tools::Rectangle& rBound, const Point& rStart, 
const Point& rEnd,
-    PolyStyle eStyle )
+ImplPolygon::ImplPolygon(const tools::Rectangle& rBound, const Point& rStart, 
const Point& rEnd,
+                         PolyStyle eStyle, const bool bClockWiseArcDirection)
 {
     const auto nWidth = rBound.GetWidth();
     const auto nHeight = rBound.GetHeight();
 
-    if( ( nWidth != 0 ) && ( nHeight != 0 ) )
+    if ((nWidth != 0) && (nHeight != 0))
     {
-        const Point aCenter( rBound.Center() );
+        const Point aCenter(rBound.Center());
         // tdf#142268 Get Top Left corner of rectangle (the rectangle is not 
always correctly created)
         const auto aBoundLeft = rBound.Left() < aCenter.X() ? rBound.Left() : 
rBound.Right();
         const auto aBoundTop = rBound.Top() < aCenter.Y() ? rBound.Top() : 
rBound.Bottom();
         const auto nRadX = o3tl::saturating_sub(aCenter.X(), aBoundLeft);
         const auto nRadY = o3tl::saturating_sub(aCenter.Y(), aBoundTop);
-        sal_uInt16  nPoints;
+        sal_uInt16 nPoints;
 
         tools::Long nRadXY;
         const bool bOverflow = o3tl::checked_multiply(nRadX, nRadY, nRadXY);
@@ -270,17 +270,29 @@ ImplPolygon::ImplPolygon( const tools::Rectangle& rBound, 
const Point& rStart, c
         double          fStep;
         sal_uInt16      nStart;
         sal_uInt16      nEnd;
-        // #i73608# If startPoint is equal to endPoint, then draw full circle 
instead of nothing (as Metafiles spec)
-        if( fDiff <= 0. )
-            fDiff += 2 * M_PI;
+
+        if (bClockWiseArcDirection == false)
+        {
+            // #i73608# If startPoint is equal to endPoint, then draw full 
circle instead of nothing (as Metafiles spec)
+            if (fDiff <= 0.)
+                fDiff += 2. * M_PI;
+        }
+        else
+        {
+            fDiff = (2. * M_PI) - fDiff;
+            if (fDiff > 2. * M_PI)
+                fDiff -= 2. * M_PI;
+        }
 
         // Proportionally shrink number of points( fDiff / (2PI) );
-        nPoints = std::max( static_cast<sal_uInt16>( ( fDiff / (2 * M_PI) ) * 
nPoints ), sal_uInt16(16) );
-        fStep = fDiff / ( nPoints - 1 );
+        nPoints = std::max(static_cast<sal_uInt16>((fDiff / (2. * M_PI)) * 
nPoints), sal_uInt16(16));
+        fStep = fDiff / (nPoints - 1);
+        if (bClockWiseArcDirection == true)
+            fStep = -fStep;
 
-        if( PolyStyle::Pie == eStyle )
+        if (PolyStyle::Pie == eStyle)
         {
-            const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
+            const Point aCenter2(FRound(fCenterX), FRound(fCenterY));
 
             nStart = 1;
             nEnd = nPoints + 1;
@@ -903,8 +915,9 @@ Polygon::Polygon( const Point& rCenter, tools::Long nRadX, 
tools::Long nRadY )
 {
 }
 
-Polygon::Polygon( const tools::Rectangle& rBound, const Point& rStart, const 
Point& rEnd,
-                  PolyStyle eStyle ) : mpImplPolygon(ImplPolygon(rBound, 
rStart, rEnd, eStyle))
+Polygon::Polygon(const tools::Rectangle& rBound, const Point& rStart, const 
Point& rEnd,
+                 PolyStyle eStyle, const bool bClockWiseArcDirection)
+    : mpImplPolygon(ImplPolygon(rBound, rStart, rEnd, eStyle, 
bClockWiseArcDirection))
 {
 }
 

Reply via email to