drawinglayer/source/processor2d/vclpixelprocessor2d.cxx |   23 -----
 vcl/headless/svpgdi.cxx                                 |   20 ++--
 vcl/opengl/gdiimpl.cxx                                  |    7 +
 vcl/qt5/Qt5Graphics_GDI.cxx                             |    6 +
 vcl/quartz/salgdicommon.cxx                             |    9 +-
 vcl/skia/gdiimpl.cxx                                    |    8 -
 vcl/source/outdev/line.cxx                              |    7 -
 vcl/source/outdev/polygon.cxx                           |   12 +-
 vcl/source/outdev/polyline.cxx                          |    9 --
 vcl/source/outdev/textline.cxx                          |    3 
 vcl/source/outdev/transparent.cxx                       |    8 -
 vcl/unx/generic/gdi/gdiimpl.cxx                         |   25 +++--
 vcl/win/gdi/gdiimpl.cxx                                 |   72 ++++++----------
 13 files changed, 97 insertions(+), 112 deletions(-)

New commits:
commit dd117712bd5692f7bf3870ba91572a0bab54ab86
Author:     Armin Le Grand <armin.le.gr...@me.com>
AuthorDate: Thu Mar 5 19:24:30 2020 +0100
Commit:     Armin Le Grand <armin.le.gr...@me.com>
CommitDate: Fri Mar 6 10:10:55 2020 +0100

    tdf#124848 partial refactor hairline logic
    
    With the handover of transformations to line
    draw calls it is no longer feasible to detect
    and prepare LineWidth stuff when the old
    office definition for hairlnes is used, a
    line width of zero. It was managed in the
    system-independent part, but now may have to
    be prepared in logic and not discrete (pixel)
    coordinates. To do so, find and cleanup all
    places where 1/1.0 was used as hairline line
    width. Adapt all seven graphic subsystems to
    handle the line width == 0/0.0 cases
    accordingly. Test as good as possible.
    
    Change-Id: I2badc045474dcd51612e50597b8406a55d9dc863
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/90057
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@me.com>

diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 4bd490dcfe78..8cff84f3d3bf 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -166,26 +166,6 @@ namespace drawinglayer::processor2d
             const bool 
bStrokeAttributeNotUsed(rSource.getStrokeAttribute().isDefault()
                 || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen());
 
-            // check if LineWidth can be simplified in world coordinates
-            double fLineWidth(rSource.getLineAttribute().getWidth());
-
-            if(basegfx::fTools::more(fLineWidth, 0.0))
-            {
-                basegfx::B2DVector aLineWidth(fLineWidth, 0.0);
-                aLineWidth = maCurrentTransformation * aLineWidth;
-                const double fWorldLineWidth(aLineWidth.getLength());
-
-                // draw simple hairline for small line widths
-                // see also RenderPolygonStrokePrimitive2D which is used if 
this try fails
-                bool bIsAntiAliasing = 
getOptionsDrawinglayer().IsAntiAliasing();
-                if (   (basegfx::fTools::lessOrEqual(fWorldLineWidth, 1.0) && 
bIsAntiAliasing)
-                    || (basegfx::fTools::lessOrEqual(fWorldLineWidth, 1.5) && 
!bIsAntiAliasing))
-                {
-                    // draw simple hairline
-                    fLineWidth = 0.0;
-                }
-            }
-
             const basegfx::BColor aLineColor(
                 maBColorModifierStack.getModifiedColor(
                     rSource.getLineAttribute().getColor()));
@@ -197,7 +177,8 @@ namespace drawinglayer::processor2d
             return mpOutputDevice->DrawPolyLineDirect(
                 maCurrentTransformation,
                 rLocalPolygon,
-                fLineWidth,
+                // tdf#124848 use LineWidth direct, do not try to solve for 
zero-case (aka hairline)
+                rSource.getLineAttribute().getWidth(),
                 fTransparency,
                 bStrokeAttributeNotUsed ? nullptr : 
&rSource.getStrokeAttribute().getDotDashArray(),
                 rSource.getLineAttribute().getLineJoin(),
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index de105c5062f9..fb4514eba37d 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -1525,22 +1525,20 @@ bool SvpSalGraphics::drawPolyLine(
     // need to check/handle LineWidth when ObjectToDevice transformation is 
used
     basegfx::B2DVector aLineWidth(rLineWidth);
     const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity());
-    const basegfx::B2DVector aDeviceLineWidth(bObjectToDeviceIsIdentity ? 
rLineWidth : rObjectToDevice * rLineWidth);
-    const bool bCorrectLineWidth(!bObjectToDeviceIsIdentity && 
aDeviceLineWidth.getX() < 1.0 && aLineWidth.getX() >= 1.0);
 
-    // on-demand inverse of ObjectToDevice transformation
-    basegfx::B2DHomMatrix aObjectToDeviceInv;
-
-    if(bCorrectLineWidth)
+    // tdf#124848 calculate-back logical LineWidth for a hairline
+    // since this implementation hands over the transformation to
+    // the graphic sub-system
+    if(aLineWidth.equalZero())
     {
-        if(aObjectToDeviceInv.isIdentity())
+        aLineWidth = basegfx::B2DVector(1.0, 1.0);
+
+        if(!bObjectToDeviceIsIdentity)
         {
-            aObjectToDeviceInv = rObjectToDevice;
+            basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice);
             aObjectToDeviceInv.invert();
+            aLineWidth = aObjectToDeviceInv * aLineWidth;
         }
-
-        // calculate-back logical LineWidth for a hairline
-        aLineWidth = aObjectToDeviceInv * basegfx::B2DVector(1.0, 1.0);
     }
 
     // PixelOffset used: Need to reflect in linear transformation
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 4a4a19c89600..25cac157a56b 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -1678,7 +1678,12 @@ bool OpenGLSalGraphicsImpl::drawPolyLine(
     // Transform to DeviceCoordinates, get DeviceLineWidth, execute 
PixelSnapHairline
     aPolyPolygonLine.transform(rObjectToDevice);
     if(bPixelSnapHairline) { aPolyPolygonLine = 
basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); }
-    const basegfx::B2DVector aLineWidth(rObjectToDevice * rLineWidth);
+
+    // tdf#124848 get correct LineWidth in discrete coordinates,
+    // take hairline case into account
+    const basegfx::B2DVector aLineWidth(rLineWidth.equalZero()
+        ? basegfx::B2DVector(1.0, 1.0)
+        : rObjectToDevice * rLineWidth);
 
     for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
     {
diff --git a/vcl/qt5/Qt5Graphics_GDI.cxx b/vcl/qt5/Qt5Graphics_GDI.cxx
index 38866ae96320..eb43811466d4 100644
--- a/vcl/qt5/Qt5Graphics_GDI.cxx
+++ b/vcl/qt5/Qt5Graphics_GDI.cxx
@@ -369,7 +369,11 @@ bool Qt5Graphics::drawPolyLine(const 
basegfx::B2DHomMatrix& rObjectToDevice,
     {
         aPolyPolygonLine = 
basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
     }
-    const basegfx::B2DVector aLineWidth(rObjectToDevice * rLineWidth);
+
+    // tdf#124848 get correct LineWidth in discrete coordinates,
+    // take hairline case into account
+    const basegfx::B2DVector aLineWidth(rLineWidth.equalZero() ? 
basegfx::B2DVector(1.0, 1.0)
+                                                               : 
rObjectToDevice * rLineWidth);
 
     // setup poly-polygon path
     QPainterPath aPath;
diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx
index a526790bb907..4ca5eede4578 100644
--- a/vcl/quartz/salgdicommon.cxx
+++ b/vcl/quartz/salgdicommon.cxx
@@ -835,10 +835,11 @@ bool AquaSalGraphics::drawPolyLine(
         return false;
 #endif
 
-    // need to check/handle LineWidth when ObjectToDevice transformation is 
used
-    const basegfx::B2DVector aDeviceLineWidth(rObjectToDevice * rLineWidth);
-    const bool bCorrectLineWidth(aDeviceLineWidth.getX() < 1.0 && 
rLineWidth.getX() >= 1.0);
-    const basegfx::B2DVector aLineWidth(bCorrectLineWidth ? rLineWidth : 
aDeviceLineWidth);
+    // tdf#124848 get correct LineWidth in discrete coordinates,
+    // take hairline case into account
+    const basegfx::B2DVector aLineWidth(rLineWidth.equalZero()
+        ? basegfx::B2DVector(1.0, 1.0)
+        : rObjectToDevice * rLineWidth);
 
     // #i101491# Aqua does not support B2DLineJoin::NONE; return false to use
     // the fallback (own geometry preparation)
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index a704ef9c5312..7dfd667e8a63 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -718,10 +718,10 @@ bool SkiaSalGraphicsImpl::drawPolyLine(const 
basegfx::B2DHomMatrix& rObjectToDev
     preDraw();
     SAL_INFO("vcl.skia", "drawpolyline(" << this << "): " << rPolyLine << ":" 
<< mLineColor);
 
-    // need to check/handle LineWidth when ObjectToDevice transformation is 
used
-    const basegfx::B2DVector aDeviceLineWidth(rObjectToDevice * rLineWidth);
-    const bool bCorrectLineWidth(aDeviceLineWidth.getX() < 1.0 && 
rLineWidth.getX() >= 1.0);
-    const basegfx::B2DVector aLineWidth(bCorrectLineWidth ? rLineWidth : 
aDeviceLineWidth);
+    // tdf#124848 get correct LineWidth in discrete coordinates,
+    // take hairline case into account
+    const basegfx::B2DVector aLineWidth(rLineWidth.equalZero() ? 
basegfx::B2DVector(1.0, 1.0)
+                                                               : 
rObjectToDevice * rLineWidth);
 
     // Skia does not support B2DLineJoin::NONE; return false to use
     // the fallback (own geometry preparation),
diff --git a/vcl/source/outdev/line.cxx b/vcl/source/outdev/line.cxx
index 3332ab711a24..e88dd383e7f3 100644
--- a/vcl/source/outdev/line.cxx
+++ b/vcl/source/outdev/line.cxx
@@ -116,7 +116,6 @@ void OutputDevice::DrawLine( const Point& rStartPt, const 
Point& rEndPt )
         // at least transform with double precision to device coordinates; 
this will
         // avoid pixel snap of single, appended lines
         const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
-        const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
         basegfx::B2DPolygon aB2DPolyLine;
 
         aB2DPolyLine.append(basegfx::B2DPoint(rStartPt.X(), rStartPt.Y()));
@@ -129,7 +128,8 @@ void OutputDevice::DrawLine( const Point& rStartPt, const 
Point& rEndPt )
             basegfx::B2DHomMatrix(),
             aB2DPolyLine,
             0.0,
-            aB2DLineWidth,
+            // tdf#124848 hairline
+            basegfx::B2DVector::getEmptyVector(),
             nullptr, // MM01
             basegfx::B2DLineJoin::NONE,
             css::drawing::LineCap_BUTT,
@@ -241,7 +241,8 @@ void OutputDevice::drawLine( basegfx::B2DPolyPolygon 
aLinePolyPolygon, const Lin
                     basegfx::B2DHomMatrix(),
                     rB2DPolygon,
                     0.0,
-                    basegfx::B2DVector(1.0,1.0),
+                    // tdf#124848 hairline
+                    basegfx::B2DVector::getEmptyVector(),
                     nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx
index c33374f3a408..c742379d39de 100644
--- a/vcl/source/outdev/polygon.cxx
+++ b/vcl/source/outdev/polygon.cxx
@@ -88,7 +88,6 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& 
rPolyPoly )
 
         if(bSuccess && IsLineColor())
         {
-            const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
             const bool bPixelSnapHairline(mnAntialiasing & 
AntialiasingFlags::PixelSnapHairline);
 
             for(auto const& rPolygon : aB2DPolyPolygon)
@@ -97,7 +96,8 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& 
rPolyPoly )
                     aTransform,
                     rPolygon,
                     0.0,
-                    aB2DLineWidth,
+                    // tdf#124848 hairline
+                    basegfx::B2DVector::getEmptyVector(),
                     nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
@@ -209,14 +209,14 @@ void OutputDevice::DrawPolygon( const tools::Polygon& 
rPoly )
 
         if(bSuccess && IsLineColor())
         {
-            const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
             const bool bPixelSnapHairline(mnAntialiasing & 
AntialiasingFlags::PixelSnapHairline);
 
             bSuccess = mpGraphics->DrawPolyLine(
                 aTransform,
                 aB2DPolygon,
                 0.0,
-                aB2DLineWidth,
+                // tdf#124848 hairline
+                basegfx::B2DVector::getEmptyVector(),
                 nullptr, // MM01
                 basegfx::B2DLineJoin::NONE,
                 css::drawing::LineCap_BUTT,
@@ -318,7 +318,6 @@ void 
OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP
 
         if(bSuccess && IsLineColor())
         {
-            const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
             const bool bPixelSnapHairline(mnAntialiasing & 
AntialiasingFlags::PixelSnapHairline);
 
             for(auto const& rPolygon : aB2DPolyPolygon)
@@ -327,7 +326,8 @@ void 
OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP
                     aTransform,
                     rPolygon,
                     0.0,
-                    aB2DLineWidth,
+                    // tdf#124848 hairline
+                    basegfx::B2DVector::getEmptyVector(),
                     nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
diff --git a/vcl/source/outdev/polyline.cxx b/vcl/source/outdev/polyline.cxx
index 161bf5fb4e52..3e2ed372e01b 100644
--- a/vcl/source/outdev/polyline.cxx
+++ b/vcl/source/outdev/polyline.cxx
@@ -65,14 +65,14 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& 
rPoly )
 
     const basegfx::B2DPolygon aB2DPolyLine(rPoly.getB2DPolygon());
     const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
-    const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
     const bool bPixelSnapHairline(mnAntialiasing & 
AntialiasingFlags::PixelSnapHairline);
 
     if(mpGraphics->DrawPolyLine(
         aTransform,
         aB2DPolyLine,
         0.0,
-        aB2DLineWidth,
+        // tdf#124848 hairline
+        basegfx::B2DVector::getEmptyVector(),
         nullptr, // MM01
         basegfx::B2DLineJoin::NONE,
         css::drawing::LineCap_BUTT,
@@ -341,8 +341,6 @@ bool OutputDevice::DrawPolyLineDirect(
     {
         // combine rObjectTransform with WorldToDevice
         const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation() * 
rObjectTransform);
-        const bool bLineWidthZero(basegfx::fTools::equalZero(fLineWidth));
-        const basegfx::B2DVector aB2DLineWidth(bLineWidthZero ? 1.0 : 
fLineWidth, bLineWidthZero ? 1.0 : fLineWidth);
         const bool bPixelSnapHairline((mnAntialiasing & 
AntialiasingFlags::PixelSnapHairline) && rB2DPolygon.count() < 1000);
 
         // draw the polyline
@@ -350,7 +348,8 @@ bool OutputDevice::DrawPolyLineDirect(
             aTransform,
             rB2DPolygon,
             fTransparency,
-            aB2DLineWidth,
+            // tdf#124848 use LineWidth direct, do not try to solve for 
zero-case (aka hairline)
+            basegfx::B2DVector(fLineWidth, fLineWidth),
             pStroke, // MM01
             eLineJoin,
             eLineCap,
diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx
index e52b02410ebd..a6eaa6b1c3a7 100644
--- a/vcl/source/outdev/textline.cxx
+++ b/vcl/source/outdev/textline.cxx
@@ -997,7 +997,8 @@ void OutputDevice::DrawWaveLine(const Point& rStartPos, 
const Point& rEndPos, lo
     if (nWaveHeight > pFontInstance->mxFontMetric->GetWavelineUnderlineSize())
     {
         nWaveHeight = pFontInstance->mxFontMetric->GetWavelineUnderlineSize();
-        nLineWidth = 1;
+        // tdf#124848 hairline
+        nLineWidth = 0;
     }
 
     const basegfx::B2DRectangle aWaveLineRectangle(nStartX, nStartY, nEndX, 
nEndY + nWaveHeight);
diff --git a/vcl/source/outdev/transparent.cxx 
b/vcl/source/outdev/transparent.cxx
index 3c4a6fb2a1c0..c6baa93ed7c3 100644
--- a/vcl/source/outdev/transparent.cxx
+++ b/vcl/source/outdev/transparent.cxx
@@ -260,7 +260,6 @@ void OutputDevice::DrawTransparent(
 
         if( bDrawnOk && IsLineColor() )
         {
-            const basegfx::B2DVector aHairlineWidth(1,1);
             const bool bPixelSnapHairline(mnAntialiasing & 
AntialiasingFlags::PixelSnapHairline);
 
             for(auto const& rPolygon : aB2DPolyPolygon)
@@ -269,7 +268,8 @@ void OutputDevice::DrawTransparent(
                     aFullTransform,
                     rPolygon,
                     fTransparency,
-                    aHairlineWidth,
+                    // tdf#124848 hairline
+                    basegfx::B2DVector::getEmptyVector(),
                     nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
@@ -383,7 +383,6 @@ bool OutputDevice::DrawTransparentNatively ( const 
tools::PolyPolygon& rPolyPoly
             mpGraphics->SetFillColor();
 
             // draw the border line
-            const basegfx::B2DVector aLineWidths( 1, 1 );
             const bool bPixelSnapHairline(mnAntialiasing & 
AntialiasingFlags::PixelSnapHairline);
 
             for(auto const& rPolygon : aB2DPolyPolygon)
@@ -392,7 +391,8 @@ bool OutputDevice::DrawTransparentNatively ( const 
tools::PolyPolygon& rPolyPoly
                     aTransform,
                     rPolygon,
                     fTransparency,
-                    aLineWidths,
+                    // tdf#124848 hairline
+                    basegfx::B2DVector::getEmptyVector(),
                     nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx
index ddbf68cda3d1..99884a4c0941 100644
--- a/vcl/unx/generic/gdi/gdiimpl.cxx
+++ b/vcl/unx/generic/gdi/gdiimpl.cxx
@@ -1665,20 +1665,27 @@ bool X11SalGraphicsImpl::drawPolyLine(
     // need to check/handle LineWidth when ObjectToDevice transformation is 
used
     basegfx::B2DVector aLineWidth(rLineWidth);
     const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity());
-    const basegfx::B2DVector aDeviceLineWidths(bObjectToDeviceIsIdentity ? 
rLineWidth : rObjectToDevice * rLineWidth);
-    const bool bCorrectLineWidth(!bObjectToDeviceIsIdentity && 
aDeviceLineWidths.getX() < 1.0 && aLineWidth.getX() >= 1.0);
     basegfx::B2DHomMatrix aObjectToDeviceInv;
 
-    if(bCorrectLineWidth)
+    // tdf#124848 calculate-back logical LineWidth for a hairline.
+    // This implementation does not hand over the transformation to
+    // the graphic sub-system, but the triangulation data is prepared
+    // view-independent based on the logic LineWidth, so we need to
+    // know it
+    if(aLineWidth.equalZero())
     {
-        if(aObjectToDeviceInv.isIdentity())
+        aLineWidth = basegfx::B2DVector(1.0, 1.0);
+
+        if(!bObjectToDeviceIsIdentity)
         {
-            aObjectToDeviceInv = rObjectToDevice;
-            aObjectToDeviceInv.invert();
-        }
+            if(aObjectToDeviceInv.isIdentity())
+            {
+                aObjectToDeviceInv = rObjectToDevice;
+                aObjectToDeviceInv.invert();
+            }
 
-        // calculate-back logical LineWidth for a hairline
-        aLineWidth = aObjectToDeviceInv * basegfx::B2DVector(1.0, 1.0);
+            aLineWidth = aObjectToDeviceInv * aLineWidth;
+        }
     }
 
     // try to access buffered data
diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx
index a26d85d1e378..08c5f7861e8e 100644
--- a/vcl/win/gdi/gdiimpl.cxx
+++ b/vcl/win/gdi/gdiimpl.cxx
@@ -2111,7 +2111,7 @@ bool WinSalGraphicsImpl::drawPolyPolygon(
         // and embed into a TransformPrimitive2D containing the transformation.
         //
         // A 2nd problem is that the NoLineJoin mode 
(basegfx::B2DLineJoin::NONE
-        // && rLineWidths > 0.0) creates polygon fill infos that are not 
reusable
+        // && !bIsHairline) creates polygon fill infos that are not reusable
         // for the fill case (see ::drawPolyLine below) - thus we would need a
         // bool and/or two system-dependent paths buffered - doable, but 
complicated.
         //
@@ -2204,7 +2204,7 @@ bool WinSalGraphicsImpl::drawPolyLine(
     const basegfx::B2DHomMatrix& rObjectToDevice,
     const basegfx::B2DPolygon& rPolygon,
     double fTransparency,
-    const basegfx::B2DVector& rLineWidths,
+    const basegfx::B2DVector& rLineWidth,
     const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
@@ -2217,14 +2217,34 @@ bool WinSalGraphicsImpl::drawPolyLine(
         return true;
     }
 
+    // need to check/handle LineWidth when ObjectToDevice transformation is 
used
+    basegfx::B2DVector aLineWidth(rLineWidth);
+    const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity());
+    const bool bIsHairline(aLineWidth.equalZero());
+
+    // tdf#124848 calculate-back logical LineWidth for a hairline
+    // since this implementation hands over the transformation to
+    // the graphic sub-system
+    if(bIsHairline)
+    {
+        aLineWidth = basegfx::B2DVector(1.0, 1.0);
+
+        if(!bObjectToDeviceIsIdentity)
+        {
+            basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice);
+            aObjectToDeviceInv.invert();
+            aLineWidth = aObjectToDeviceInv * aLineWidth;
+        }
+    }
+
     Gdiplus::Graphics aGraphics(mrParent.getHDC());
     const sal_uInt8 aTrans = static_cast<sal_uInt8>(basegfx::fround( 255 * 
(1.0 - fTransparency) ));
     const Gdiplus::Color aTestColor(aTrans, maLineColor.GetRed(), 
maLineColor.GetGreen(), maLineColor.GetBlue());
-    Gdiplus::Pen aPen(aTestColor.GetValue(), 
Gdiplus::REAL(rLineWidths.getX()));
+    Gdiplus::Pen aPen(aTestColor.GetValue(), Gdiplus::REAL(aLineWidth.getX()));
     bool bNoLineJoin(false);
 
     // Set full (Object-to-Device) transformation - if used
-    if(rObjectToDevice.isIdentity())
+    if(bObjectToDeviceIsIdentity)
     {
         aGraphics.ResetTransform();
     }
@@ -2246,7 +2266,7 @@ bool WinSalGraphicsImpl::drawPolyLine(
     {
         case basegfx::B2DLineJoin::NONE :
         {
-            if(basegfx::fTools::more(rLineWidths.getX(), 0.0))
+            if(!bIsHairline)
             {
                 bNoLineJoin = true;
             }
@@ -2315,44 +2335,12 @@ bool WinSalGraphicsImpl::drawPolyLine(
     // activate to stroke directly
     if(bDoDirectGDIPlusStroke && bStrokeUsed)
     {
-        // tdf#130478
-        // Unfortunately GDIPlus wants to have the dash pattern relative to 
line width
-        // which gets problematic due to the good old office's hairline 
definition. This
-        // means that we do not *have* the real line width here, but 0.0 - or 
in the case
-        // of GDIPlus (here) 1.0.
-        // This is 'corrected' in several locations, e.g. 
OutputDevice::DrawPolyLineDirect
-        // to 1.0 and 
VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect to 0.0.
-        // This would need some cleanup what will be highly problematic due to 
the usage
-        // of hairlines with line width of 0.0 being a pixel always and 
leading to different
-        // visualizations. More bad - the potential of having pretty 
'invisible' lines
-        // in unexpected places when zooming far out. Another problematic 
aspect of that hairline
-        // definition is that this makes hairlines per definition 
view-transformation dependent
-        // regarding their 'core' line width and the area they cover - handled 
in Primitives,
-        // but not easy to do.
-        // The way out here is to calculate back a single pixel from device to 
logic
-        // (Object coordinates) to have the 'logic', view-dependent line width 
and use it.
-        // That works for the cost of a matrix inversion - sigh.
+        // tdf#124848 the fix of tdf#130478 that was needed here before
+        // gets much easier when already handling the hairline case above,
+        // the back-calculated logical linewidth is already here, just use it.
+        // Still be careful - a zero LineWidth *should* not happen, but...
         std::vector<Gdiplus::REAL> aDashArray(pStroke->size());
-        double fFactor(1.0);
-
-        if(rLineWidths.getX() <= 1.0)
-        {
-            // no 'real' line width, need to calculate back the logic line 
width
-            // for a one pixel hairline
-            basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice);
-            aObjectToDeviceInv.invert();
-            const basegfx::B2DVector aOnePixel(aObjectToDeviceInv * 
basegfx::B2DVector(1.0, 1.0));
-
-            if(aOnePixel.getX() > 0.0)
-            {
-                fFactor = 1.0 / aOnePixel.getX();
-            }
-        }
-        else
-        {
-            // use logic line width
-            fFactor = 1.0 / rLineWidths.getX();
-        }
+        const double fFactor(aLineWidth.equalZero() ? 1.0 : 1.0 / 
aLineWidth.getX());
 
         for(size_t a(0); a < pStroke->size(); a++)
         {
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to