tdf#151844 Make EMR_EXTSELECTCLIPRGN factor in WinOrg coordinates

EMR_EXTSELECTCLIPRGN would not factor in WinOrg coordinates which would
give the clip box wrong coordinates causing some graphics to look
chopped in the wrong way.

Change-Id: I4f9a1b1c27fc276d188d0d865991795dab48dce5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142110
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
diff --git a/emfio/inc/mtftools.hxx b/emfio/inc/mtftools.hxx
index 997f228..b4fd639 100644
--- a/emfio/inc/mtftools.hxx
+++ b/emfio/inc/mtftools.hxx
@@ -731,6 +731,7 @@ namespace emfio
        void                ScaleDevExt(double fX, double fY);

        void                SetWinOrg(const Point& rPoint, bool bIsEMF = false);
        Point               GetWinOrg() { return Point(mnWinOrgX, mnWinOrgY); }
        void                SetWinOrgOffset(sal_Int32 nX, sal_Int32 nY);
        void                SetWinExt(const Size& rSize, bool bIsEMF = false);
        void                ScaleWinExt(double fX, double fY);
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index 99adda3..75f2b900 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -69,6 +69,7 @@ class Test : public UnoApiXmlTest
    void TestEmfPlusDrawPathWithMiterLimit();
    void TestEmfPlusFillClosedCurve();
    void TestExtTextOutOpaqueAndClipTransform();
    void TestNegativeWinOrg();

    void TestBitBltStretchBltWMF();
    void TestExtTextOutOpaqueAndClipWMF();
@@ -122,6 +123,7 @@ public:
    CPPUNIT_TEST(TestEmfPlusDrawPathWithMiterLimit);
    CPPUNIT_TEST(TestEmfPlusFillClosedCurve);
    CPPUNIT_TEST(TestExtTextOutOpaqueAndClipTransform);
    CPPUNIT_TEST(TestNegativeWinOrg);

    CPPUNIT_TEST(TestBitBltStretchBltWMF);
    CPPUNIT_TEST(TestExtTextOutOpaqueAndClipWMF);
@@ -1203,6 +1205,24 @@ void Test::TestExtTextOutOpaqueAndClipTransform()
                "#000000");
}

void Test::TestNegativeWinOrg()
{
    Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestNegativeWinOrg.emf");
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
    drawinglayer::Primitive2dXmlDump dumper;
    xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence));
    CPPUNIT_ASSERT(pDocument);

    // The crop box (EMR_EXTSELECTCLIPRGN) would not factor in WinOrg coordinates
    // and be lower and more to the right than it actually is which would cut the
    // text in the emf above in half.
    assertXPath(pDocument, aXPathPrefix + "mask/group[1]/mask/polypolygon", 1);
    assertXPath(pDocument, aXPathPrefix + "mask/group[1]/mask/polypolygon", "minx", "0");
    assertXPath(pDocument, aXPathPrefix + "mask/group[1]/mask/polypolygon", "miny", "272");
    assertXPath(pDocument, aXPathPrefix + "mask/group[1]/mask/polypolygon", "maxx", "6800");
    assertXPath(pDocument, aXPathPrefix + "mask/group[1]/mask/polypolygon", "maxy", "644");
}

void Test::TestBitBltStretchBltWMF()
{
    // tdf#55058 tdf#142722 WMF records: BITBLT, STRETCHBLT.
diff --git a/emfio/qa/cppunit/emf/data/TestNegativeWinOrg.emf b/emfio/qa/cppunit/emf/data/TestNegativeWinOrg.emf
new file mode 100644
index 0000000..d428f4c
--- /dev/null
+++ b/emfio/qa/cppunit/emf/data/TestNegativeWinOrg.emf
Binary files differ
diff --git a/emfio/source/reader/emfreader.cxx b/emfio/source/reader/emfreader.cxx
index 7baa7c8..207d837 100644
--- a/emfio/source/reader/emfreader.cxx
+++ b/emfio/source/reader/emfreader.cxx
@@ -332,7 +332,7 @@ SvStream& operator>>(SvStream& rInStream, BLENDFUNCTION& rBlendFun)
    return rInStream;
}

bool ImplReadRegion( basegfx::B2DPolyPolygon& rPolyPoly, SvStream& rStream, sal_uInt32 nLen )
bool ImplReadRegion( basegfx::B2DPolyPolygon& rPolyPoly, SvStream& rStream, sal_uInt32 nLen, Point aWinOrg )
{
    if (nLen < 32) // 32 bytes - Size of RegionDataHeader
        return false;
@@ -369,6 +369,10 @@ bool ImplReadRegion( basegfx::B2DPolyPolygon& rPolyPoly, SvStream& rStream, sal_
        rStream.ReadInt32(nTop);
        rStream.ReadInt32(nRight);
        rStream.ReadInt32(nBottom);
        nLeft += aWinOrg.X();
        nRight += aWinOrg.X();
        nTop += aWinOrg.Y();
        nBottom += aWinOrg.Y();
        rPolyPoly.append( basegfx::utils::createPolygonFromRect( ::basegfx::B2DRectangle( nLeft, nTop, nRight, nBottom ) ) );
        SAL_INFO("emfio", "\t\t" << i << " Left: " << nLeft << ", top: " << nTop << ", right: " << nRight << ", bottom: " << nBottom);
    }
@@ -1348,7 +1352,7 @@ namespace emfio
                            {
                                basegfx::B2DPolyPolygon aPolyPoly;
                                if (cbRgnData)
                                    ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize);
                                    ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize, GetWinOrg());
                                const tools::PolyPolygon aPolyPolygon(aPolyPoly);
                                SetClipPath(aPolyPolygon, static_cast<RegionMode>(nClippingMode), false);
                            }
@@ -1930,7 +1934,7 @@ namespace emfio
                            mpInputStream->ReadUInt32( nRgnDataSize ).ReadUInt32( nIndex );
                            nRemainingRecSize -= 24;

                            if (ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize))
                            if (ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize, GetWinOrg()))
                            {
                                Push();
                                SelectObject( nIndex );
@@ -1955,7 +1959,7 @@ namespace emfio
                            mpInputStream->ReadUInt32( nRgnDataSize );
                            nRemainingRecSize -= 20;

                            if (ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize))
                            if (ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize, GetWinOrg()))
                            {
                                tools::PolyPolygon aPolyPolygon(aPolyPoly);
                                DrawPolyPolygon( aPolyPolygon );