do not apply line dashing in drawinglayer (tdf#136957)

basegfx::utils::applyLineDashing() is not as good as the actual
VCL backend dashing, and there are some rounding errors because of
all the canvas transformation matrices or whatever, which leads
to the drawing problem. So use LineInfo to carry the dashing
information.
As a part of this change, also make LineInfo use doubles instead
of ints. The use of transformation matrices means that the values
may be fractional and less than one.

Change-Id: Ia5ac7d266cab344b7137052c81fbd96c1ce28003
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114710
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx
index 24f7f3f..a9df9eb 100644
--- a/cppcanvas/source/mtfrenderer/implrenderer.cxx
+++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx
@@ -161,13 +161,13 @@ namespace
        // interpret dash info only if explicitly enabled as
        // style
        const ::basegfx::B2DSize aDistance( rLineInfo.GetDistance(), 0 );
        const double nDistance( (rState.mapModeTransform * aDistance).getX() );
        const double nDistance( (rState.mapModeTransform * aDistance).getLength() );

        const ::basegfx::B2DSize aDashLen( rLineInfo.GetDashLen(), 0 );
        const double nDashLen( (rState.mapModeTransform * aDashLen).getX() );
        const double nDashLen( (rState.mapModeTransform * aDashLen).getLength() );

        const ::basegfx::B2DSize aDotLen( rLineInfo.GetDotLen(), 0 );
        const double nDotLen( (rState.mapModeTransform * aDotLen).getX() );
        const double nDotLen( (rState.mapModeTransform * aDotLen).getLength() );

        const sal_Int32 nNumArryEntries( 2*rLineInfo.GetDashCount() +
                                         2*rLineInfo.GetDotCount() );
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index 6f690ca..0dc0904 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -1574,24 +1574,11 @@ void VclMetafileProcessor2D::processPolygonStrokePrimitive2D(
        if (basegfx::fTools::more(rLine.getWidth(), 0.0))
        {
            const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
            basegfx::B2DPolyPolygon aHairLinePolyPolygon;

            if (0.0 == rStroke.getFullDotDashLen())
            {
                aHairLinePolyPolygon.append(rBasePolygon);
            }
            else
            {
                basegfx::utils::applyLineDashing(rBasePolygon, rStroke.getDotDashArray(),
                                                 &aHairLinePolyPolygon, nullptr,
                                                 rStroke.getFullDotDashLen());
            }

            const basegfx::BColor aHairlineColor(
                maBColorModifierStack.getModifiedColor(rLine.getColor()));
            mpOutputDevice->SetLineColor(Color(aHairlineColor));
            mpOutputDevice->SetFillColor();
            aHairLinePolyPolygon.transform(maCurrentTransformation);

            // use the transformed line width
            LineInfo aLineInfo(LineStyle::Solid,
@@ -1599,6 +1586,48 @@ void VclMetafileProcessor2D::processPolygonStrokePrimitive2D(
            aLineInfo.SetLineJoin(rLine.getLineJoin());
            aLineInfo.SetLineCap(rLine.getLineCap());

            basegfx::B2DPolyPolygon aHairLinePolyPolygon;
            if (0.0 == rStroke.getFullDotDashLen())
            {
                aHairLinePolyPolygon.append(rBasePolygon);
            }
            else if (rStroke.getDotDashArray().size() == 2)
            {
                aHairLinePolyPolygon.append(rBasePolygon);
                // This will be used by setupStrokeAttributes() in cppcanvas.
                aLineInfo.SetStyle(LineStyle::Dash);
                aLineInfo.SetDashCount(1);
                aLineInfo.SetDashLen(
                    basegfx::fround(getTransformedLineWidth(rStroke.getDotDashArray()[0])));
                aLineInfo.SetDistance(
                    basegfx::fround(getTransformedLineWidth(rStroke.getDotDashArray()[1])));
            }
            else if (rStroke.getDotDashArray().size() == 4
                     && rStroke.getDotDashArray()[1] == rStroke.getDotDashArray()[3])
            {
                aHairLinePolyPolygon.append(rBasePolygon);
                // This will be used by setupStrokeAttributes() in cppcanvas.
                aLineInfo.SetStyle(LineStyle::Dash);
                aLineInfo.SetDashCount(1);
                aLineInfo.SetDashLen(
                    basegfx::fround(getTransformedLineWidth(rStroke.getDotDashArray()[0])));
                aLineInfo.SetDistance(
                    basegfx::fround(getTransformedLineWidth(rStroke.getDotDashArray()[1])));
                aLineInfo.SetDotCount(1);
                aLineInfo.SetDotLen(
                    basegfx::fround(getTransformedLineWidth(rStroke.getDotDashArray()[2])));
            }
            else
            {
                // LineInfo can hold only limited info about dashing, apply dashing manually
                // if LineInfo cannot describe it. That should not happen though.
                SAL_WARN("drawinglayer", "dotdash array cannot be converted to LineInfo");
                basegfx::utils::applyLineDashing(rBasePolygon, rStroke.getDotDashArray(),
                                                 &aHairLinePolyPolygon, nullptr,
                                                 rStroke.getFullDotDashLen());
            }
            aHairLinePolyPolygon.transform(maCurrentTransformation);

            for (sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
            {
                const basegfx::B2DPolygon& aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
diff --git a/include/svx/xdash.hxx b/include/svx/xdash.hxx
index e1fca6b..e789830 100644
--- a/include/svx/xdash.hxx
+++ b/include/svx/xdash.hxx
@@ -31,32 +31,32 @@
class SVXCORE_DLLPUBLIC XDash final
{
    css::drawing::DashStyle  eDash;
    sal_uInt32               nDotLen;
    sal_uInt16               nDots;
    sal_uInt16               nDashes;
    sal_uInt32               nDashLen;
    sal_uInt32               nDistance;
    double                   nDotLen;
    double                   nDashLen;
    double                   nDistance;

public:
          XDash(css::drawing::DashStyle eDash = css::drawing::DashStyle_RECT,
                sal_uInt16 nDots = 1, sal_uInt32 nDotLen = 20,
                sal_uInt16 nDashes = 1, sal_uInt32 nDashLen = 20, sal_uInt32 nDistance = 20);
                sal_uInt16 nDots = 1, double nDotLen = 20,
                sal_uInt16 nDashes = 1, double nDashLen = 20, double nDistance = 20);

    bool operator==(const XDash& rDash) const;

    void SetDashStyle(css::drawing::DashStyle eNewStyle) { eDash = eNewStyle; }
    void SetDots(sal_uInt16 nNewDots)                    { nDots = nNewDots; }
    void SetDotLen(sal_uInt32 nNewDotLen)                { nDotLen = nNewDotLen; }
    void SetDotLen(double nNewDotLen)                    { nDotLen = nNewDotLen; }
    void SetDashes(sal_uInt16 nNewDashes)                { nDashes = nNewDashes; }
    void SetDashLen(sal_uInt32 nNewDashLen)              { nDashLen = nNewDashLen; }
    void SetDistance(sal_uInt32 nNewDistance)            { nDistance = nNewDistance; }
    void SetDashLen(double nNewDashLen)                  { nDashLen = nNewDashLen; }
    void SetDistance(double nNewDistance)                { nDistance = nNewDistance; }

    css::drawing::DashStyle  GetDashStyle() const        { return eDash; }
    sal_uInt16               GetDots() const             { return nDots; }
    sal_uInt32               GetDotLen() const           { return nDotLen; }
    double                   GetDotLen() const           { return nDotLen; }
    sal_uInt16               GetDashes() const           { return nDashes; }
    sal_uInt32               GetDashLen() const          { return nDashLen; }
    sal_uInt32               GetDistance() const         { return nDistance; }
    double                   GetDashLen() const          { return nDashLen; }
    double                   GetDistance() const         { return nDistance; }

    // XDash is translated into an array of doubles which describe the lengths of the
    // dashes, dots and empty passages. It returns the complete length of the full DashDot
diff --git a/include/vcl/lineinfo.hxx b/include/vcl/lineinfo.hxx
index 09cc074..73ed0d3 100644
--- a/include/vcl/lineinfo.hxx
+++ b/include/vcl/lineinfo.hxx
@@ -32,10 +32,10 @@ namespace basegfx { class B2DPolyPolygon; }

struct ImplLineInfo
{
    sal_Int32               mnWidth;
    sal_Int32               mnDashLen;
    sal_Int32               mnDotLen;
    sal_Int32               mnDistance;
    double                  mnWidth;
    double                  mnDashLen;
    double                  mnDotLen;
    double                  mnDistance;

    basegfx::B2DLineJoin    meLineJoin;
    css::drawing::LineCap   meLineCap;
@@ -53,7 +53,7 @@ struct ImplLineInfo
class VCL_DLLPUBLIC LineInfo
{
public:
                    LineInfo( LineStyle eLineStyle = LineStyle::Solid, sal_Int32 nWidth = 0 );
                    LineInfo( LineStyle eLineStyle = LineStyle::Solid, double nWidth = 0 );
                    LineInfo( const LineInfo& rLineInfo );
                    LineInfo( LineInfo&& rLineInfo );
                    ~LineInfo();
@@ -66,23 +66,23 @@ public:
    void            SetStyle( LineStyle eStyle );
    LineStyle       GetStyle() const { return mpImplLineInfo->meStyle; }

    void            SetWidth( sal_Int32 nWidth );
    sal_Int32       GetWidth() const { return mpImplLineInfo->mnWidth; }
    void            SetWidth( double nWidth );
    double          GetWidth() const { return mpImplLineInfo->mnWidth; }

    void            SetDashCount( sal_uInt16 nDashCount );
    sal_uInt16      GetDashCount() const { return mpImplLineInfo->mnDashCount; }

    void            SetDashLen( sal_Int32 nDashLen );
    sal_Int32       GetDashLen() const { return mpImplLineInfo->mnDashLen; }
    void            SetDashLen( double nDashLen );
    double          GetDashLen() const { return mpImplLineInfo->mnDashLen; }

    void            SetDotCount( sal_uInt16 nDotCount );
    sal_uInt16      GetDotCount() const { return mpImplLineInfo->mnDotCount; }

    void            SetDotLen( sal_Int32 nDotLen );
    sal_Int32       GetDotLen() const { return mpImplLineInfo->mnDotLen; }
    void            SetDotLen( double nDotLen );
    double          GetDotLen() const { return mpImplLineInfo->mnDotLen; }

    void            SetDistance( sal_Int32 nDistance );
    sal_Int32       GetDistance() const { return mpImplLineInfo->mnDistance; }
    void            SetDistance( double nDistance );
    double          GetDistance() const { return mpImplLineInfo->mnDistance; }

    void SetLineJoin(basegfx::B2DLineJoin eLineJoin);
    basegfx::B2DLineJoin GetLineJoin() const { return mpImplLineInfo->meLineJoin; }
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index 7d3acad..6c12ac0 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -2854,10 +2854,10 @@ void SdOOXMLExportTest2::testTdf126741()

    CPPUNIT_ASSERT_EQUAL(drawing::LineStyle_DASH, rStyleItem.GetValue());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), rDashItem.GetDashValue().GetDots());
    CPPUNIT_ASSERT_EQUAL(sal_uInt32(800), rDashItem.GetDashValue().GetDotLen());
    CPPUNIT_ASSERT_EQUAL(800.0, rDashItem.GetDashValue().GetDotLen());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), rDashItem.GetDashValue().GetDashes());
    CPPUNIT_ASSERT_EQUAL(sal_uInt32(100), rDashItem.GetDashValue().GetDashLen());
    CPPUNIT_ASSERT_EQUAL(sal_uInt32(300), rDashItem.GetDashValue().GetDistance());
    CPPUNIT_ASSERT_EQUAL(100.0, rDashItem.GetDashValue().GetDashLen());
    CPPUNIT_ASSERT_EQUAL(300.0, rDashItem.GetDashValue().GetDistance());

    xDocShRef->DoClose();
}
diff --git a/sd/qa/unit/uiimpress.cxx b/sd/qa/unit/uiimpress.cxx
index 9a1ab0a..7d00456 100644
--- a/sd/qa/unit/uiimpress.cxx
+++ b/sd/qa/unit/uiimpress.cxx
@@ -31,6 +31,7 @@
#include <svx/xfillit0.hxx>
#include <svx/xflclit.hxx>
#include <svx/xflgrit.hxx>
#include <svx/xlndsit.hxx>
#include <SlideSorterViewShell.hxx>
#include <SlideSorter.hxx>
#include <controller/SlideSorterController.hxx>
@@ -632,27 +633,12 @@ CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf134053)
    SdrObject* pShape = pActualPage->GetObj(0);
    CPPUNIT_ASSERT_MESSAGE("No Shape", pShape);

    // Break line into single dash and dot objects
    SdrView* pView = pViewShell->GetView();
    pView->MarkObj(pShape, pView->GetSdrPageView());
    dispatchCommand(mxComponent, ".uno:ConvertIntoMetafile", {});
    dispatchCommand(mxComponent, ".uno:Break", {});

    // Measure the rendered length of dash, dot and distance
    SdrObject* pDash = pActualPage->GetObj(0);
    const tools::Rectangle& rBoundDashRect = pDash->GetCurrentBoundRect();
    const double fDashLength(rBoundDashRect.GetWidth());
    SdrObject* pDot = pActualPage->GetObj(1);
    const tools::Rectangle& rBoundDotRect = pDot->GetCurrentBoundRect();
    const double fDotLength(rBoundDotRect.GetWidth());
    const double fDistance(rBoundDotRect.Left() - rBoundDashRect.Right());
    XDash dash = pShape->GetMergedItem(XATTR_LINEDASH).GetDashValue();

    // Because 0% is not possible as dash length (as of June 2020) 1% is used in the fix.
    // For that a larger delta is here allowed to the ideal value than needed for
    // rounding errors.
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Distance", 2117, fDistance, 12);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Dot length", 706, fDotLength, 12);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Dash length", 2822, fDashLength, 12);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Distance", 399.0, dash.GetDistance());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Dot length", 301.0, dash.GetDotLen());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Dash length", 1.0, dash.GetDashLen());
}

CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testSpellOnlineParameter)
diff --git a/svx/source/xoutdev/xattr.cxx b/svx/source/xoutdev/xattr.cxx
index 27f1186..42109442 100644
--- a/svx/source/xoutdev/xattr.cxx
+++ b/svx/source/xoutdev/xattr.cxx
@@ -400,12 +400,12 @@ sal_uInt16 XLineStyleItem::GetValueCount() const
    return 3;
}

XDash::XDash(css::drawing::DashStyle eTheDash, sal_uInt16 nTheDots, sal_uInt32 nTheDotLen,
             sal_uInt16 nTheDashes, sal_uInt32 nTheDashLen, sal_uInt32 nTheDistance) :
XDash::XDash(css::drawing::DashStyle eTheDash, sal_uInt16 nTheDots, double nTheDotLen,
             sal_uInt16 nTheDashes, double nTheDashLen, double nTheDistance) :
    eDash(eTheDash),
    nDotLen(nTheDotLen),
    nDots(nTheDots),
    nDashes(nTheDashes),
    nDotLen(nTheDotLen),
    nDashLen(nTheDashLen),
    nDistance(nTheDistance)
{
@@ -433,9 +433,9 @@ double XDash::CreateDotDashArray(::std::vector< double >& rDotDashArray, double 
    rDotDashArray.resize( nNumDotDashArray, 0.0 );
    sal_uInt16 a;
    sal_uInt16 nIns(0);
    double fDashDotDistance = static_cast<double>(GetDistance());
    double fSingleDashLen = static_cast<double>(GetDashLen());
    double fSingleDotLen = static_cast<double>(GetDotLen());
    double fDashDotDistance = GetDistance();
    double fSingleDashLen = GetDashLen();
    double fSingleDotLen = GetDotLen();

    if (fLineWidth == 0.0)
        fLineWidth = SMALLEST_DASH_WIDTH;
diff --git a/vcl/source/filter/idxf/dxfvec.cxx b/vcl/source/filter/idxf/dxfvec.cxx
index fb1ff64..58b4d1f 100644
--- a/vcl/source/filter/idxf/dxfvec.cxx
+++ b/vcl/source/filter/idxf/dxfvec.cxx
@@ -207,10 +207,10 @@ LineInfo DXFTransform::Transform(const DXFLineInfo& aDXFLineInfo) const
    aLineInfo.SetStyle( aDXFLineInfo.eStyle );
    aLineInfo.SetWidth( 0 );
    aLineInfo.SetDashCount( static_cast< sal_uInt16 >( aDXFLineInfo.nDashCount ) );
    aLineInfo.SetDashLen( static_cast<sal_Int32>(aDXFLineInfo.fDashLen * scale + 0.5) );
    aLineInfo.SetDashLen( aDXFLineInfo.fDashLen * scale );
    aLineInfo.SetDotCount( static_cast< sal_uInt16 >( aDXFLineInfo.nDotCount ) );
    aLineInfo.SetDotLen( static_cast<sal_Int32>(aDXFLineInfo.fDotLen * scale + 0.5) );
    aLineInfo.SetDistance( static_cast<sal_Int32>(aDXFLineInfo.fDistance * scale + 0.5) );
    aLineInfo.SetDotLen( aDXFLineInfo.fDotLen * scale );
    aLineInfo.SetDistance( aDXFLineInfo.fDistance * scale );

    if ( aLineInfo.GetDashCount() > 0 && aLineInfo.GetDashLen() == 0 )
        aLineInfo.SetDashLen(1);
diff --git a/vcl/source/gdi/lineinfo.cxx b/vcl/source/gdi/lineinfo.cxx
index 94c1d1b..345eeb2 100644
--- a/vcl/source/gdi/lineinfo.cxx
+++ b/vcl/source/gdi/lineinfo.cxx
@@ -53,7 +53,7 @@ inline bool ImplLineInfo::operator==( const ImplLineInfo& rB ) const
}


LineInfo::LineInfo( LineStyle eStyle, sal_Int32 nWidth ) : mpImplLineInfo()
LineInfo::LineInfo( LineStyle eStyle, double nWidth ) : mpImplLineInfo()
{
    mpImplLineInfo->meStyle = eStyle;
    mpImplLineInfo->mnWidth = nWidth;
@@ -79,7 +79,7 @@ void LineInfo::SetStyle( LineStyle eStyle )
    mpImplLineInfo->meStyle = eStyle;
}

void LineInfo::SetWidth( sal_Int32 nWidth )
void LineInfo::SetWidth( double nWidth )
{
    mpImplLineInfo->mnWidth = nWidth;
}
@@ -89,7 +89,7 @@ void LineInfo::SetDashCount( sal_uInt16 nDashCount )
    mpImplLineInfo->mnDashCount = nDashCount;
}

void LineInfo::SetDashLen( sal_Int32 nDashLen )
void LineInfo::SetDashLen( double nDashLen )
{
    mpImplLineInfo->mnDashLen = nDashLen;
}
@@ -99,31 +99,24 @@ void LineInfo::SetDotCount( sal_uInt16 nDotCount )
    mpImplLineInfo->mnDotCount = nDotCount;
}

void LineInfo::SetDotLen( sal_Int32 nDotLen )
void LineInfo::SetDotLen( double nDotLen )
{
    mpImplLineInfo->mnDotLen = nDotLen;
}

void LineInfo::SetDistance( sal_Int32 nDistance )
void LineInfo::SetDistance( double nDistance )
{
    mpImplLineInfo->mnDistance = nDistance;
}

void LineInfo::SetLineJoin(basegfx::B2DLineJoin eLineJoin)
{

    if(eLineJoin != mpImplLineInfo->meLineJoin)
    {
        mpImplLineInfo->meLineJoin = eLineJoin;
    }
    mpImplLineInfo->meLineJoin = eLineJoin;
}

void LineInfo::SetLineCap(css::drawing::LineCap eLineCap)
{
    if(eLineCap != mpImplLineInfo->meLineCap)
    {
        mpImplLineInfo->meLineCap = eLineCap;
    }
    mpImplLineInfo->meLineCap = eLineCap;
}

bool LineInfo::IsDefault() const
@@ -139,7 +132,8 @@ SvStream& ReadLineInfo( SvStream& rIStm, LineInfo& rLineInfo )
    sal_uInt16          nTmp16(0);
    sal_Int32       nTmp32(0);

    rIStm.ReadUInt16( nTmp16 ); rLineInfo.mpImplLineInfo->meStyle = static_cast<LineStyle>(nTmp16);
    rIStm.ReadUInt16( nTmp16 );
    rLineInfo.mpImplLineInfo->meStyle = static_cast<LineStyle>(nTmp16);
    rIStm.ReadInt32( nTmp32 );
    rLineInfo.mpImplLineInfo->mnWidth = nTmp32;

@@ -157,13 +151,24 @@ SvStream& ReadLineInfo( SvStream& rIStm, LineInfo& rLineInfo )
    if( aCompat.GetVersion() >= 3 )
    {
        // version 3
        rIStm.ReadUInt16( nTmp16 ); rLineInfo.mpImplLineInfo->meLineJoin = static_cast<basegfx::B2DLineJoin>(nTmp16);
        rIStm.ReadUInt16( nTmp16 );
        rLineInfo.mpImplLineInfo->meLineJoin = static_cast<basegfx::B2DLineJoin>(nTmp16);
    }

    if( aCompat.GetVersion() >= 4 )
    {
        // version 4
        rIStm.ReadUInt16( nTmp16 ); rLineInfo.mpImplLineInfo->meLineCap = static_cast<css::drawing::LineCap>(nTmp16);
        rIStm.ReadUInt16( nTmp16 );
        rLineInfo.mpImplLineInfo->meLineCap = static_cast<css::drawing::LineCap>(nTmp16);
    }

    if( aCompat.GetVersion() >= 5 )
    {
        // version 5
        rIStm.ReadDouble( rLineInfo.mpImplLineInfo->mnWidth );
        rIStm.ReadDouble( rLineInfo.mpImplLineInfo->mnDashLen );
        rIStm.ReadDouble( rLineInfo.mpImplLineInfo->mnDotLen );
        rIStm.ReadDouble( rLineInfo.mpImplLineInfo->mnDistance );
    }

    return rIStm;
@@ -171,18 +176,18 @@ SvStream& ReadLineInfo( SvStream& rIStm, LineInfo& rLineInfo )

SvStream& WriteLineInfo( SvStream& rOStm, const LineInfo& rLineInfo )
{
    VersionCompatWrite aCompat( rOStm, 4 );
    VersionCompatWrite aCompat( rOStm, 5 );

    // version 1
    rOStm.WriteUInt16( static_cast<sal_uInt16>(rLineInfo.mpImplLineInfo->meStyle) )
         .WriteInt32( rLineInfo.mpImplLineInfo->mnWidth );
         .WriteInt32( basegfx::fround( rLineInfo.mpImplLineInfo->mnWidth ));

    // since version2
    rOStm.WriteUInt16( rLineInfo.mpImplLineInfo->mnDashCount )
         .WriteInt32( rLineInfo.mpImplLineInfo->mnDashLen );
         .WriteInt32( basegfx::fround( rLineInfo.mpImplLineInfo->mnDashLen ));
    rOStm.WriteUInt16( rLineInfo.mpImplLineInfo->mnDotCount )
         .WriteInt32( rLineInfo.mpImplLineInfo->mnDotLen );
    rOStm.WriteInt32( rLineInfo.mpImplLineInfo->mnDistance );
         .WriteInt32( basegfx::fround( rLineInfo.mpImplLineInfo->mnDotLen ));
    rOStm.WriteInt32( basegfx::fround( rLineInfo.mpImplLineInfo->mnDistance ));

    // since version3
    rOStm.WriteUInt16( static_cast<sal_uInt16>(rLineInfo.mpImplLineInfo->meLineJoin) );
@@ -190,6 +195,12 @@ SvStream& WriteLineInfo( SvStream& rOStm, const LineInfo& rLineInfo )
    // since version4
    rOStm.WriteUInt16( static_cast<sal_uInt16>(rLineInfo.mpImplLineInfo->meLineCap) );

    // since version5
    rOStm.WriteDouble( rLineInfo.mpImplLineInfo->mnWidth );
    rOStm.WriteDouble( rLineInfo.mpImplLineInfo->mnDashLen );
    rOStm.WriteDouble( rLineInfo.mpImplLineInfo->mnDotLen );
    rOStm.WriteDouble( rLineInfo.mpImplLineInfo->mnDistance );

    return rOStm;
}

diff --git a/vcl/source/outdev/polyline.cxx b/vcl/source/outdev/polyline.cxx
index 5da5ccd..e3ec909 100644
--- a/vcl/source/outdev/polyline.cxx
+++ b/vcl/source/outdev/polyline.cxx
@@ -122,7 +122,7 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly, const LineInfo& rL
    {
        DrawPolyLine(
            rPoly.getB2DPolygon(),
            static_cast< double >(rLineInfo.GetWidth()),
            rLineInfo.GetWidth(),
            rLineInfo.GetLineJoin(),
            rLineInfo.GetLineCap(),
            basegfx::deg2rad(15.0) /* default fMiterMinimumAngle, value not available in LineInfo */);
@@ -147,7 +147,7 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon,
    {
        LineInfo aLineInfo;
        if( fLineWidth != 0.0 )
            aLineInfo.SetWidth( static_cast<tools::Long>(fLineWidth+0.5) );
            aLineInfo.SetWidth( fLineWidth );

        const tools::Polygon aToolsPolygon( rB2DPolygon );
        mpMetaFile->AddAction( new MetaPolyLineAction( aToolsPolygon, aLineInfo ) );
@@ -235,7 +235,7 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon,
        const tools::Polygon aToolsPolygon( rB2DPolygon );
        LineInfo aLineInfo;
        if( fLineWidth != 0.0 )
            aLineInfo.SetWidth( static_cast<tools::Long>(fLineWidth+0.5) );
            aLineInfo.SetWidth( fLineWidth );

        drawPolyLine( aToolsPolygon, aLineInfo );
    }
@@ -310,7 +310,7 @@ bool OutputDevice::DrawPolyLineDirect(
        {
            LineInfo aLineInfo;
            if( fLineWidth != 0.0 )
                aLineInfo.SetWidth( static_cast<tools::Long>(fLineWidth+0.5) );
                aLineInfo.SetWidth( fLineWidth );
            // Transport known information, might be needed
            aLineInfo.SetLineJoin(eLineJoin);
            aLineInfo.SetLineCap(eLineCap);