diff options
author | Armin Le Grand <Armin.Le.Grand@me.com> | 2020-03-05 19:24:30 +0100 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2020-03-06 10:10:55 +0100 |
commit | dd117712bd5692f7bf3870ba91572a0bab54ab86 (patch) | |
tree | bde473f22e43cc320e3960c331de7051d01ad77e | |
parent | a3c8951da607d63ac7ffc76a062bb76208ca5ff3 (diff) |
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.Grand@me.com>
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 23 | ||||
-rw-r--r-- | vcl/headless/svpgdi.cxx | 20 | ||||
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 7 | ||||
-rw-r--r-- | vcl/qt5/Qt5Graphics_GDI.cxx | 6 | ||||
-rw-r--r-- | vcl/quartz/salgdicommon.cxx | 9 | ||||
-rw-r--r-- | vcl/skia/gdiimpl.cxx | 8 | ||||
-rw-r--r-- | vcl/source/outdev/line.cxx | 7 | ||||
-rw-r--r-- | vcl/source/outdev/polygon.cxx | 12 | ||||
-rw-r--r-- | vcl/source/outdev/polyline.cxx | 9 | ||||
-rw-r--r-- | vcl/source/outdev/textline.cxx | 3 | ||||
-rw-r--r-- | vcl/source/outdev/transparent.cxx | 8 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/gdiimpl.cxx | 25 | ||||
-rw-r--r-- | vcl/win/gdi/gdiimpl.cxx | 72 |
13 files changed, 97 insertions, 112 deletions
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++) { |