tdf#74702 vcl: make helper funcs for ImplDrawWaveLine() and ImplDrawWavePixel()

Unit tests written for Printer and OutputDevice, note that I might have
uncovered a bug.

Change-Id: Ic8e6e02ce0df349fc6fb6a3334105c1e6dfa3f36
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113563
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 95df09d..e2a4b4d1 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1077,6 +1077,11 @@
    static
    SAL_DLLPRIVATE tools::Long         ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo, tools::Long nWidth, const OUString& rStr, DrawTextFlags nStyle, const vcl::ITextLayout& _rLayout );
    SAL_DLLPRIVATE float        approximate_char_width() const;

    virtual bool shouldDrawWavePixelAsRect(tools::Long nLineWidth) const;
    virtual void SetWaveLineColors(Color const& rColor, tools::Long nLineWidth);
    virtual Size GetWaveLineSize(tools::Long nLineWidth) const;

private:
    SAL_DLLPRIVATE void         ImplInitTextColor();

@@ -1084,8 +1089,8 @@
    SAL_DLLPRIVATE void         ImplDrawSpecialText( SalLayout& );
    SAL_DLLPRIVATE void         ImplDrawTextRect( tools::Long nBaseX, tools::Long nBaseY, tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight );

    SAL_DLLPRIVATE static void  ImplDrawWavePixel( tools::Long nOriginX, tools::Long nOriginY, tools::Long nCurX, tools::Long nCurY, Degree10 nOrientation, SalGraphics* pGraphics, const OutputDevice& rOutDev,
                                                   bool bDrawPixAsRect, tools::Long nPixWidth, tools::Long nPixHeight );
    SAL_DLLPRIVATE void  ImplDrawWavePixel( tools::Long nOriginX, tools::Long nOriginY, tools::Long nCurX, tools::Long nCurY, tools::Long nWidth, Degree10 nOrientation, SalGraphics* pGraphics, const OutputDevice& rOutDev, tools::Long nPixWidth, tools::Long nPixHeight );

    SAL_DLLPRIVATE void         ImplDrawWaveLine( tools::Long nBaseX, tools::Long nBaseY, tools::Long nStartX, tools::Long nStartY, tools::Long nWidth, tools::Long nHeight, tools::Long nLineWidth, Degree10 nOrientation, const Color& rColor );
    SAL_DLLPRIVATE void         ImplDrawWaveTextLine( tools::Long nBaseX, tools::Long nBaseY, tools::Long nX, tools::Long nY, tools::Long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove );
    SAL_DLLPRIVATE void         ImplDrawStraightTextLine( tools::Long nBaseX, tools::Long nBaseY, tools::Long nX, tools::Long nY, tools::Long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove );
diff --git a/include/vcl/print.hxx b/include/vcl/print.hxx
index 1ffce12..b4db139 100644
--- a/include/vcl/print.hxx
+++ b/include/vcl/print.hxx
@@ -248,6 +248,10 @@

    virtual void                SetFontOrientation( LogicalFontInstance* const pFontInstance ) const override;

    bool                        shouldDrawWavePixelAsRect(tools::Long) const override { return true; }
    void                        SetWaveLineColors(Color const& rColor, tools::Long) override;
    Size                        GetWaveLineSize(tools::Long nLineWidth) const override;

public:
                                Printer();
                                Printer( const JobSetup& rJobSetup );
diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx
index bc70ba1..d9aa34a 100644
--- a/vcl/qa/cppunit/outdev.cxx
+++ b/vcl/qa/cppunit/outdev.cxx
@@ -49,6 +49,8 @@
    void testTransparentFillColor();
    void testFillColor();
    void testSystemTextColor();
    void testShouldDrawWavePixelAsRect();
    void testGetWaveLineSize();

    CPPUNIT_TEST_SUITE(VclOutdevTest);
    CPPUNIT_TEST(testVirtualDevice);
@@ -71,6 +73,8 @@
    CPPUNIT_TEST(testTransparentFillColor);
    CPPUNIT_TEST(testFillColor);
    CPPUNIT_TEST(testSystemTextColor);
    CPPUNIT_TEST(testShouldDrawWavePixelAsRect);
    CPPUNIT_TEST(testGetWaveLineSize);
    CPPUNIT_TEST_SUITE_END();
};

@@ -549,6 +553,78 @@
    }
}

namespace
{
class WaveLineTester : public OutputDevice
{
public:
    WaveLineTester()
        : OutputDevice(OUTDEV_VIRDEV)
    {
    }

    bool AcquireGraphics() const { return true; }
    void ReleaseGraphics(bool) {}
    bool UsePolyPolygonForComplexGradient() { return false; }

    bool testShouldDrawWavePixelAsRect(tools::Long nLineWidth)
    {
        return shouldDrawWavePixelAsRect(nLineWidth);
    }

    Size testGetWaveLineSize(tools::Long nLineWidth) { return GetWaveLineSize(nLineWidth); }
};

class WaveLineTesterPrinter : public Printer
{
public:
    WaveLineTesterPrinter() {}

    bool AcquireGraphics() const { return true; }
    void ReleaseGraphics(bool) {}
    bool UsePolyPolygonForComplexGradient() { return false; }

    Size testGetWaveLineSize(tools::Long nLineWidth) { return GetWaveLineSize(nLineWidth); }
};
}

void VclOutdevTest::testShouldDrawWavePixelAsRect()
{
    ScopedVclPtrInstance<WaveLineTester> pTestOutDev;

    CPPUNIT_ASSERT(!pTestOutDev->testShouldDrawWavePixelAsRect(0));
    CPPUNIT_ASSERT(!pTestOutDev->testShouldDrawWavePixelAsRect(1));

    CPPUNIT_ASSERT(pTestOutDev->testShouldDrawWavePixelAsRect(10));
}

void VclOutdevTest::testGetWaveLineSize()
{
    {
        ScopedVclPtrInstance<WaveLineTester> pTestOutDev;

        pTestOutDev->SetDPIX(96);
        pTestOutDev->SetDPIY(96);

        CPPUNIT_ASSERT_EQUAL(Size(1, 1), pTestOutDev->testGetWaveLineSize(0));
        CPPUNIT_ASSERT_EQUAL(Size(1, 1), pTestOutDev->testGetWaveLineSize(1));

        CPPUNIT_ASSERT_EQUAL(Size(10, 10), pTestOutDev->testGetWaveLineSize(10));
    }

    {
        ScopedVclPtrInstance<WaveLineTesterPrinter> pTestOutDev;

        pTestOutDev->SetDPIX(96);
        pTestOutDev->SetDPIY(96);

        CPPUNIT_ASSERT_EQUAL(Size(0, 0), pTestOutDev->testGetWaveLineSize(0));
        CPPUNIT_ASSERT_EQUAL(Size(1, 1), pTestOutDev->testGetWaveLineSize(1));

        CPPUNIT_ASSERT_EQUAL(Size(10, 10), pTestOutDev->testGetWaveLineSize(10));
    }
}

CPPUNIT_TEST_SUITE_REGISTRATION(VclOutdevTest);

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx
index 593744b..6b6b070 100644
--- a/vcl/source/gdi/print.cxx
+++ b/vcl/source/gdi/print.cxx
@@ -1750,6 +1750,25 @@
    return aInfo;
}

void Printer::SetWaveLineColors(Color const& rColor, tools::Long)
{
    if (mbLineColor || mbInitLineColor)
    {
        mpGraphics->SetLineColor();
        mbInitLineColor = true;
    }

    mpGraphics->SetFillColor(rColor);
    mbInitFillColor = true;
}

Size Printer::GetWaveLineSize(tools::Long nLineWidth) const
{
    // FIXME - do we have a bug here? If the linewidth is 0, then we will return
    // Size(0, 0) - is this correct?
    return Size(nLineWidth, ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY);
}

void Printer::SetSystemTextColor(SystemTextColorFlags, bool)
{
    SetTextColor(COL_BLACK);
diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx
index 2ce85be..9fd8254 100644
--- a/vcl/source/outdev/textline.cxx
+++ b/vcl/source/outdev/textline.cxx
@@ -113,21 +113,20 @@

void OutputDevice::ImplDrawWavePixel( tools::Long nOriginX, tools::Long nOriginY,
                                      tools::Long nCurX, tools::Long nCurY,
                                      tools::Long nWidth,
                                      Degree10 nOrientation,
                                      SalGraphics* pGraphics,
                                      const OutputDevice& rOutDev,
                                      bool bDrawPixAsRect,
                                      tools::Long nPixWidth, tools::Long nPixHeight )
{
    if ( nOrientation )
    if (nOrientation)
    {
        Point aPoint( nOriginX, nOriginY );
        aPoint.RotateAround( nCurX, nCurY, nOrientation );
    }

    if ( bDrawPixAsRect )
    if (shouldDrawWavePixelAsRect(nWidth))
    {

        pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, rOutDev );
    }
    else
@@ -136,6 +135,43 @@
    }
}

bool OutputDevice::shouldDrawWavePixelAsRect(tools::Long nLineWidth) const
{
    if (nLineWidth > 1)
        return true;

    return false;
}

void OutputDevice::SetWaveLineColors(Color const& rColor, tools::Long nLineWidth)
{
    // On printers that output pixel via DrawRect()
    if (nLineWidth > 1)
    {
        if (mbLineColor || mbInitLineColor)
        {
            mpGraphics->SetLineColor();
            mbInitLineColor = true;
        }

        mpGraphics->SetFillColor( rColor );
        mbInitFillColor = true;
    }
    else
    {
        mpGraphics->SetLineColor( rColor );
        mbInitLineColor = true;
    }
}

Size OutputDevice::GetWaveLineSize(tools::Long nLineWidth) const
{
    if (nLineWidth > 1)
        return Size(nLineWidth, ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY);

    return Size(1, 1);
}

void OutputDevice::ImplDrawWaveLine( tools::Long nBaseX, tools::Long nBaseY,
                                     tools::Long nDistX, tools::Long nDistY,
                                     tools::Long nWidth, tools::Long nHeight,
@@ -172,39 +208,20 @@
        tools::Long    nDiffY = nHeight-1;
        tools::Long    nCount = nWidth;
        tools::Long    nOffY = -1;
        tools::Long    nPixWidth;
        tools::Long    nPixHeight;
        bool    bDrawPixAsRect;
        // On printers that output pixel via DrawRect()
        if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
        {
            if ( mbLineColor || mbInitLineColor )
            {
                mpGraphics->SetLineColor();
                mbInitLineColor = true;
            }
            mpGraphics->SetFillColor( rColor );
            mbInitFillColor = true;
            bDrawPixAsRect  = true;
            nPixWidth       = nLineWidth;
            nPixHeight      = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
        }
        else
        {
            mpGraphics->SetLineColor( rColor );
            mbInitLineColor = true;
            nPixWidth       = 1;
            nPixHeight      = 1;
            bDrawPixAsRect  = false;
        }

        SetWaveLineColors(rColor, nLineWidth);
        Size aSize(GetWaveLineSize(nLineWidth));

        tools::Long nPixWidth = aSize.Width();
        tools::Long nPixHeight = aSize.Height();

        if ( !nDiffY )
        {
            while ( nWidth )
            {
                ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
                ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nLineWidth, nOrientation,
                                   mpGraphics, *this,
                                   bDrawPixAsRect, nPixWidth, nPixHeight );
                                   nPixWidth, nPixHeight );
                nCurX++;
                nWidth--;
            }
@@ -217,17 +234,17 @@
            {
                for( tools::Long i = nDiffY; i; --i )
                {
                    ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
                    ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nLineWidth, nOrientation,
                                       mpGraphics, *this,
                                       bDrawPixAsRect, nPixWidth, nPixHeight );
                                       nPixWidth, nPixHeight );
                    nCurX++;
                    nCurY += nOffY;
                }
                for( tools::Long i = nDiffX; i; --i )
                {
                    ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
                    ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nLineWidth, nOrientation,
                                       mpGraphics, *this,
                                       bDrawPixAsRect, nPixWidth, nPixHeight );
                                       nPixWidth, nPixHeight );
                    nCurX++;
                }
                nOffY = -nOffY;
@@ -237,18 +254,18 @@
            {
                for( tools::Long i = nDiffY; i && nFreq; --i, --nFreq )
                {
                    ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
                    ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nLineWidth, nOrientation,
                                       mpGraphics, *this,
                                       bDrawPixAsRect, nPixWidth, nPixHeight );
                                       nPixWidth, nPixHeight );
                    nCurX++;
                    nCurY += nOffY;

                }
                for( tools::Long i = nDiffX; i && nFreq; --i, --nFreq )
                {
                    ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
                    ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nLineWidth, nOrientation,
                                       mpGraphics, *this,
                                       bDrawPixAsRect, nPixWidth, nPixHeight );
                                       nPixWidth, nPixHeight );
                    nCurX++;
                }
            }