diff options
author | Armin Le Grand (Collabora) <Armin.Le.Grand@me.com> | 2020-02-06 18:53:12 +0100 |
---|---|---|
committer | Tor Lillqvist <tml@collabora.com> | 2020-02-11 07:19:01 +0100 |
commit | c069861bf9a32c826cbc86a086a774eba49c4e6f (patch) | |
tree | aa4e543b4f8fe795daaee315694e18b10b848e99 | |
parent | tdf#129519 Fix crash during WebDAV lock refresh (diff) | |
download | core-c069861bf9a32c826cbc86a086a774eba49c4e6f.tar.gz core-c069861bf9a32c826cbc86a086a774eba49c4e6f.zip |
tdf#130478 Enhance Dashed line drawing on all systems
For more info and explanation including state of process
information and discussion(s) see task please.
Adding corrections for gerrit build
Cherry-picked 5f61c9fe99ac93087b898adddbb4d4733f1fcd07:
Adaptions made and checked that Caio fat line draw
works as expected. Surprisingly some new files were
created which I removed here again.
Also needs to be cherry-picked is:
9c9f76dd5b6fb115e521ac6568673c7a10879192
which will enable direct dash paint for Cairo.
Not done here due to not sure if I can do two
cherry-picks in one run and it's lust a view lines,
so -compared to this one- should be not difficult.
Change-Id: Ie10fb8093a86459dee80db5ab4355b47e46c1f8c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88130
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88284
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Tor Lillqvist <tml@collabora.com>
30 files changed, 487 insertions, 199 deletions
diff --git a/cui/source/dialogs/screenshotannotationdlg.cxx b/cui/source/dialogs/screenshotannotationdlg.cxx index 8c3f6cfc528f..89ff425a5714 100644 --- a/cui/source/dialogs/screenshotannotationdlg.cxx +++ b/cui/source/dialogs/screenshotannotationdlg.cxx @@ -460,6 +460,7 @@ void ScreenshotAnnotationDlg_Impl::PaintControlDataEntry( aPolygon, fLineWidth, fTransparency, + nullptr, // MM01 basegfx::B2DLineJoin::Round)) { // no transparency, draw without diff --git a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx index ea2e9c9aede6..9861f6f09722 100644 --- a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx @@ -293,6 +293,7 @@ namespace drawinglayer maLineAttribute(rLineAttribute), maStrokeAttribute(rStrokeAttribute) { + // MM01: keep these - these are no curve-decompposers but just checks // simplify curve segments: moved here to not need to use it // at VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect maPolygon = basegfx::utils::simplifyCurveSegments(maPolygon); @@ -306,6 +307,7 @@ namespace drawinglayer maLineAttribute(rLineAttribute), maStrokeAttribute() { + // MM01: keep these - these are no curve-decompposers but just checks // simplify curve segments: moved here to not need to use it // at VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect maPolygon = basegfx::utils::simplifyCurveSegments(maPolygon); diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index e5deac2936e5..692b2ed272de 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -107,7 +107,7 @@ namespace drawinglayer void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency) { - if(!rSource.getB2DPolyPolygon().count()) + if(!rSource.getB2DPolyPolygon().count() || fTransparency < 0.0 || fTransparency >= 1.0) { // no geometry, done return; @@ -127,7 +127,7 @@ namespace drawinglayer { const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon()); - if(!rLocalPolygon.count()) + if(!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0) { // no geometry, done return true; @@ -149,41 +149,28 @@ namespace drawinglayer bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency) { - if(!rSource.getB2DPolygon().count()) + const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon()); + + if(!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0) { // no geometry, done return true; } - // get geometry data, prepare hairline data - const basegfx::B2DPolygon& aLocalPolygon(rSource.getB2DPolygon()); - basegfx::B2DPolyPolygon aHairLinePolyPolygon; - - // simplify curve segments - // moved to PolygonStrokePrimitive2D::PolygonStrokePrimitive2D - // aLocalPolygon = basegfx::utils::simplifyCurveSegments(aLocalPolygon); - - if(rSource.getStrokeAttribute().isDefault() || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen()) - { - // no line dashing, just copy - aHairLinePolyPolygon.append(aLocalPolygon); - } - else + if (basegfx::B2DLineJoin::NONE == rSource.getLineAttribute().getLineJoin() + && css::drawing::LineCap_BUTT != rSource.getLineAttribute().getLineCap()) { - // apply LineStyle - basegfx::utils::applyLineDashing( - aLocalPolygon, - rSource.getStrokeAttribute().getDotDashArray(), - &aHairLinePolyPolygon, - nullptr, - rSource.getStrokeAttribute().getFullDotDashLen()); + // better use decompose to get that combination done for now, see discussion + // at https://bugs.documentfoundation.org/show_bug.cgi?id=130478#c17 and ff + return false; } - if(!aHairLinePolyPolygon.count()) - { - // no geometry, done - return true; - } + // MM01: Radically change here - no dismantle/applyLineDashing, + // let that happen low-level at DrawPolyLineDirect implementations + // to open up for buffering and evtl. direct draw with sys-dep + // graphic systems. Check for stroke is in use + 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()); @@ -212,42 +199,17 @@ namespace drawinglayer mpOutputDevice->SetFillColor(); mpOutputDevice->SetLineColor(Color(aLineColor)); - // do not transform self - // aHairLinePolyPolygon.transform(maCurrentTransformation); - - bool bHasPoints(false); - bool bTryWorked(false); - - for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++) - { - const basegfx::B2DPolygon& aSingle(aHairLinePolyPolygon.getB2DPolygon(a)); - - if(aSingle.count()) - { - bHasPoints = true; - - if(mpOutputDevice->DrawPolyLineDirect( - maCurrentTransformation, - aSingle, - fLineWidth, - fTransparency, - rSource.getLineAttribute().getLineJoin(), - rSource.getLineAttribute().getLineCap(), - rSource.getLineAttribute().getMiterMinimumAngle() - /* false bBypassAACheck, default*/)) - { - bTryWorked = true; - } - } - } - - if(!bTryWorked && !bHasPoints) - { - // no geometry despite try - bTryWorked = true; - } - - return bTryWorked; + // MM01 draw direct, hand over dash data if available + return mpOutputDevice->DrawPolyLineDirect( + maCurrentTransformation, + rLocalPolygon, + fLineWidth, + fTransparency, + bStrokeAttributeNotUsed ? nullptr : &rSource.getStrokeAttribute().getDotDashArray(), + rSource.getLineAttribute().getLineJoin(), + rSource.getLineAttribute().getLineCap(), + rSource.getLineAttribute().getMiterMinimumAngle() + /* false bBypassAACheck, default*/); } void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index 6d3bbb02e54d..34057545128e 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -802,6 +802,7 @@ public: const basegfx::B2DPolygon& rB2DPolygon, double fLineWidth = 0.0, double fTransparency = 0.0, + const std::vector< double >* = nullptr, // MM01 basegfx::B2DLineJoin eLineJoin = basegfx::B2DLineJoin::NONE, css::drawing::LineCap eLineCap = css::drawing::LineCap_BUTT, double fMiterMinimumAngle = basegfx::deg2rad(15.0), diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index c4453c7f4560..8dcdcc5df44c 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -20,6 +20,8 @@ #include <config_features.h> #include <memory> +#include <numeric> + #ifndef IOS #include <headless/svpgdi.hxx> #endif @@ -789,6 +791,7 @@ void SvpSalGraphics::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) aPoly, 0.0, basegfx::B2DVector(1.0, 1.0), + nullptr, // MM01 basegfx::B2DLineJoin::Miter, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0) /*default*/, @@ -1057,18 +1060,22 @@ private: // need to be compared with to check for data validity bool mbNoJoin; bool mbAntiAliasB2DDraw; + std::vector< double > maStroke; public: SystemDependentData_CairoPath( basegfx::SystemDependentDataManager& rSystemDependentDataManager, cairo_path_t* pCairoPath, bool bNoJoin, - bool bAntiAliasB2DDraw); + bool bAntiAliasB2DDraw, + const std::vector< double >* pStroke); // MM01 virtual ~SystemDependentData_CairoPath() override; + // read access cairo_path_t* getCairoPath() { return mpCairoPath; } bool getNoJoin() const { return mbNoJoin; } bool getAntiAliasB2DDraw() const { return mbAntiAliasB2DDraw; } + const std::vector< double >& getStroke() const { return maStroke; } virtual sal_Int64 estimateUsageInBytes() const override; }; @@ -1077,12 +1084,18 @@ SystemDependentData_CairoPath::SystemDependentData_CairoPath( basegfx::SystemDependentDataManager& rSystemDependentDataManager, cairo_path_t* pCairoPath, bool bNoJoin, - bool bAntiAliasB2DDraw) + bool bAntiAliasB2DDraw, + const std::vector< double >* pStroke) : basegfx::SystemDependentData(rSystemDependentDataManager), mpCairoPath(pCairoPath), mbNoJoin(bNoJoin), - mbAntiAliasB2DDraw(bAntiAliasB2DDraw) + mbAntiAliasB2DDraw(bAntiAliasB2DDraw), + maStroke() { + if(nullptr != pStroke) + { + maStroke = *pStroke; + } } SystemDependentData_CairoPath::~SystemDependentData_CairoPath() @@ -1114,7 +1127,8 @@ bool SvpSalGraphics::drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolyLine, double fTransparency, - const basegfx::B2DVector& rLineWidths, + const basegfx::B2DVector& rLineWidth, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, @@ -1145,7 +1159,8 @@ bool SvpSalGraphics::drawPolyLine( rObjectToDevice, rPolyLine, fTransparency, - rLineWidths, + rLineWidth, + pStroke, // MM01 eLineJoin, eLineCap, fMiterMinimumAngle, @@ -1167,7 +1182,8 @@ bool SvpSalGraphics::drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolyLine, double fTransparency, - const basegfx::B2DVector& rLineWidths, + const basegfx::B2DVector& rLineWidth, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, @@ -1180,10 +1196,10 @@ bool SvpSalGraphics::drawPolyLine( } // need to check/handle LineWidth when ObjectToDevice transformation is used - basegfx::B2DVector aLineWidths(rLineWidths); + basegfx::B2DVector aLineWidth(rLineWidth); const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity()); - const basegfx::B2DVector aDeviceLineWidths(bObjectToDeviceIsIdentity ? rLineWidths : rObjectToDevice * rLineWidths); - const bool bCorrectLineWidth(!bObjectToDeviceIsIdentity && aDeviceLineWidths.getX() < 1.0 && aLineWidths.getX() >= 1.0); + 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; @@ -1197,7 +1213,7 @@ bool SvpSalGraphics::drawPolyLine( } // calculate-back logical LineWidth for a hairline - aLineWidths = aObjectToDeviceInv * basegfx::B2DVector(1.0, 1.0); + aLineWidth = aObjectToDeviceInv * basegfx::B2DVector(1.0, 1.0); } // PixelOffset used: Need to reflect in linear transformation @@ -1227,8 +1243,6 @@ bool SvpSalGraphics::drawPolyLine( // set linear transformation cairo_set_matrix(cr, &aMatrix); - const bool bNoJoin((basegfx::B2DLineJoin::NONE == eLineJoin && basegfx::fTools::more(aLineWidths.getX(), 0.0))); - // setup line attributes cairo_line_join_t eCairoLineJoin = CAIRO_LINE_JOIN_MITER; switch (eLineJoin) @@ -1279,78 +1293,118 @@ bool SvpSalGraphics::drawPolyLine( cairo_set_line_join(cr, eCairoLineJoin); cairo_set_line_cap(cr, eCairoLineCap); - cairo_set_line_width(cr, aLineWidths.getX()); + cairo_set_line_width(cr, aLineWidth.getX()); cairo_set_miter_limit(cr, fMiterLimit); - bool bDone = false; - bool bIsTrivial = isTrivial(rPolyLine); + // try to access buffered data + const bool bIsTrivial(isTrivial(rPolyLine)); + std::shared_ptr<SystemDependentData_CairoPath> pSystemDependentData_CairoPath( + bIsTrivial ? nullptr : rPolyLine.getSystemDependentData<SystemDependentData_CairoPath>()); - if (!bIsTrivial) + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + + if(pSystemDependentData_CairoPath) { - // try to access buffered data - std::shared_ptr<SystemDependentData_CairoPath> pSystemDependentData_CairoPath( - rPolyLine.getSystemDependentData<SystemDependentData_CairoPath>()); + // MM01 - check on stroke change. Used against not used, or if both used, + // equal or different? + const bool bStrokeWasUsed(!pSystemDependentData_CairoPath->getStroke().empty()); - if(pSystemDependentData_CairoPath) + if(bStrokeWasUsed != bStrokeUsed + || (bStrokeUsed && *pStroke != pSystemDependentData_CairoPath->getStroke())) { - // check data validity - if(nullptr == pSystemDependentData_CairoPath->getCairoPath() - || pSystemDependentData_CairoPath->getNoJoin() != bNoJoin - || pSystemDependentData_CairoPath->getAntiAliasB2DDraw() != bAntiAliasB2DDraw - || bPixelSnapHairline /*tdf#124700*/ ) - { - // data invalid, forget - pSystemDependentData_CairoPath.reset(); - } + // data invalid, forget + pSystemDependentData_CairoPath.reset(); } + } - if(pSystemDependentData_CairoPath) + // check for basegfx::B2DLineJoin::NONE to react accordingly + const bool bNoJoin((basegfx::B2DLineJoin::NONE == eLineJoin + && basegfx::fTools::more(aLineWidth.getX(), 0.0))); + + if(pSystemDependentData_CairoPath) + { + // check data validity + if(nullptr == pSystemDependentData_CairoPath->getCairoPath() + || pSystemDependentData_CairoPath->getNoJoin() != bNoJoin + || pSystemDependentData_CairoPath->getAntiAliasB2DDraw() != bAntiAliasB2DDraw + || bPixelSnapHairline /*tdf#124700*/ ) { - // re-use data - cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath()); - bDone = true; + // data invalid, forget + pSystemDependentData_CairoPath.reset(); } } - if (!bDone) + if(pSystemDependentData_CairoPath) + { + // re-use data + cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath()); + } + else { // create data - if (!bNoJoin) + // MM01 need to do line dashing as fallback stuff here now + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if(bStrokeUsed) { - // PixelOffset now reflected in linear transformation used - AddPolygonToPath( - cr, - rPolyLine, - rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset - !bAntiAliasB2DDraw, - bPixelSnapHairline); + // apply LineStyle + basegfx::utils::applyLineDashing( + rPolyLine, // source + *pStroke, // pattern + &aPolyPolygonLine, // traget for lines + nullptr, // target for gaps + fDotDashLength); // full length if available } else { - const sal_uInt32 nPointCount(rPolyLine.count()); - const sal_uInt32 nEdgeCount(rPolyLine.isClosed() ? nPointCount : nPointCount - 1); - basegfx::B2DPolygon aEdge; + // no line dashing, just copy + aPolyPolygonLine.append(rPolyLine); + } - aEdge.append(rPolyLine.getB2DPoint(0)); - aEdge.append(basegfx::B2DPoint(0.0, 0.0)); + // MM01 checked/verified for Cairo + for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); - for (sal_uInt32 i(0); i < nEdgeCount; i++) + if (!bNoJoin) { - const sal_uInt32 nNextIndex((i + 1) % nPointCount); - aEdge.setB2DPoint(1, rPolyLine.getB2DPoint(nNextIndex)); - aEdge.setNextControlPoint(0, rPolyLine.getNextControlPoint(i)); - aEdge.setPrevControlPoint(1, rPolyLine.getPrevControlPoint(nNextIndex)); - // PixelOffset now reflected in linear transformation used AddPolygonToPath( cr, - aEdge, + aPolyLine, rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset !bAntiAliasB2DDraw, bPixelSnapHairline); + } + else + { + const sal_uInt32 nPointCount(aPolyLine.count()); + const sal_uInt32 nEdgeCount(aPolyLine.isClosed() ? nPointCount : nPointCount - 1); + basegfx::B2DPolygon aEdge; + + aEdge.append(aPolyLine.getB2DPoint(0)); + aEdge.append(basegfx::B2DPoint(0.0, 0.0)); - // prepare next step - aEdge.setB2DPoint(0, aEdge.getB2DPoint(1)); + for (sal_uInt32 i(0); i < nEdgeCount; i++) + { + const sal_uInt32 nNextIndex((i + 1) % nPointCount); + aEdge.setB2DPoint(1, aPolyLine.getB2DPoint(nNextIndex)); + aEdge.setNextControlPoint(0, aPolyLine.getNextControlPoint(i)); + aEdge.setPrevControlPoint(1, aPolyLine.getPrevControlPoint(nNextIndex)); + + // PixelOffset now reflected in linear transformation used + AddPolygonToPath( + cr, + aEdge, + rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset + !bAntiAliasB2DDraw, + bPixelSnapHairline); + + // prepare next step + aEdge.setB2DPoint(0, aEdge.getB2DPoint(1)); + } } } @@ -1361,7 +1415,8 @@ bool SvpSalGraphics::drawPolyLine( ImplGetSystemDependentDataManager(), cairo_copy_path(cr), bNoJoin, - bAntiAliasB2DDraw); + bAntiAliasB2DDraw, + pStroke); } } @@ -1472,7 +1527,8 @@ bool SvpSalGraphics::drawPolyPolygon( ImplGetSystemDependentDataManager(), cairo_copy_path(cr), false, - false); + false, + nullptr); } } diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index 9ee269aa18a5..ea7be8c0733c 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -117,6 +117,7 @@ public: const basegfx::B2DPolygon& rPolyLine, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, @@ -214,6 +215,7 @@ public: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx index 132a64327e42..8d3f8c95ce7b 100644 --- a/vcl/inc/openglgdiimpl.hxx +++ b/vcl/inc/openglgdiimpl.hxx @@ -260,6 +260,7 @@ public: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/inc/qt5/Qt5Graphics.hxx b/vcl/inc/qt5/Qt5Graphics.hxx index 9430be94a112..5b50f9975d70 100644..100755 --- a/vcl/inc/qt5/Qt5Graphics.hxx +++ b/vcl/inc/qt5/Qt5Graphics.hxx @@ -119,9 +119,10 @@ public: const PolyFlags* const* pFlgAry) override; virtual bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&, double fTransparency, - const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap eLineCap, double fMiterMinimumAngle, - bool bPixelSnapHairline) override; + const basegfx::B2DVector& rLineWidths, + const std::vector<double>* pStroke, // MM01 + basegfx::B2DLineJoin, css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, bool bPixelSnapHairline) override; virtual bool drawGradient(const tools::PolyPolygon&, const Gradient&) override; virtual void copyArea(long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index 70b4ddad47f1..e9e9f4905e5e 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -238,6 +238,7 @@ public: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index 1106a1eed981..7ce17fa38385 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -248,6 +248,7 @@ public: const basegfx::B2DPolygon& i_rPolygon, double i_fTransparency, const basegfx::B2DVector& i_rLineWidth, + const std::vector< double >* i_pStroke, // MM01 basegfx::B2DLineJoin i_eLineJoin, css::drawing::LineCap i_eLineCap, double i_fMiterMinimumAngle, @@ -476,6 +477,7 @@ protected: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx index a6dc4a808ee9..887d1b49bbaf 100644 --- a/vcl/inc/salgdiimpl.hxx +++ b/vcl/inc/salgdiimpl.hxx @@ -111,6 +111,7 @@ public: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h index efe1bc7bfa3f..c5eaf1975626 100644 --- a/vcl/inc/unx/genpspgraphics.h +++ b/vcl/inc/unx/genpspgraphics.h @@ -135,6 +135,7 @@ public: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index 97be62230a68..f979a3841b49 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -168,6 +168,7 @@ public: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidth, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index cc59322b3098..08061db3c3ea 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -230,6 +230,7 @@ protected: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidth, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index dfd916f9e4c7..4e58196e4b01 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -26,6 +26,7 @@ #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <basegfx/polygon/b2dlinegeometry.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolygontriangulator.hxx> #include <basegfx/polygon/b2dpolypolygoncutter.hxx> #include <basegfx/polygon/b2dtrapezoid.hxx> @@ -42,6 +43,7 @@ #include <cmath> #include <vector> +#include <numeric> #include <glm/gtc/type_ptr.hpp> #include <glm/gtx/norm.hpp> @@ -1553,6 +1555,7 @@ void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pP aPoly, 0.0, basegfx::B2DVector(1.0, 1.0), + nullptr, // MM01 basegfx::B2DLineJoin::Miter, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0) /*default*/, @@ -1630,6 +1633,7 @@ bool OpenGLSalGraphicsImpl::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidth, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, @@ -1637,28 +1641,60 @@ bool OpenGLSalGraphicsImpl::drawPolyLine( { VCL_GL_INFO("::drawPolyLine " << rPolygon.getB2DRange()); + // MM01 check done for simple reasons + if(!rPolygon.count() || fTransparency < 0.0 || fTransparency > 1.0) + { + return true; + } + + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if(bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing( + rPolygon, // source + *pStroke, // pattern + &aPolyPolygonLine, // traget for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing, just copy + aPolyPolygonLine.append(rPolygon); + } + // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline - basegfx::B2DPolygon aPolyLine(rPolygon); - aPolyLine.transform(rObjectToDevice); - if(bPixelSnapHairline) { aPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyLine); } + aPolyPolygonLine.transform(rObjectToDevice); + if(bPixelSnapHairline) { aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); } const basegfx::B2DVector aLineWidth(rObjectToDevice * rLineWidth); - // addDrawPolyLine() assumes that there are no duplicate points in the - // polygon. - // basegfx::B2DPolygon aPolygon(rPolygon); - aPolyLine.removeDoublePoints(); + for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + // addDrawPolyLine() assumes that there are no duplicate points in the polygon + basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + basegfx::utils::simplifyCurveSegments(aPolyLine); + aPolyLine.removeDoublePoints(); - mpRenderList->addDrawPolyLine( - aPolyLine, - fTransparency, - aLineWidth, - eLineJoin, - eLineCap, - fMiterMinimumAngle, - mnLineColor, - mrParent.getAntiAliasB2DDraw()); + mpRenderList->addDrawPolyLine( + aPolyLine, + fTransparency, + aLineWidth, + eLineJoin, + eLineCap, + fMiterMinimumAngle, + mnLineColor, + mrParent.getAntiAliasB2DDraw()); + + // MM01: not sure - maybe this can be moved out of this loop, but to + // keep on the safe side for now, do not relly change something for now + PostBatchDraw(); + } - PostBatchDraw(); return true; } diff --git a/vcl/qt5/Qt5Graphics_GDI.cxx b/vcl/qt5/Qt5Graphics_GDI.cxx index 851d222f0ab7..afca58868076 100644..100755 --- a/vcl/qt5/Qt5Graphics_GDI.cxx +++ b/vcl/qt5/Qt5Graphics_GDI.cxx @@ -29,7 +29,9 @@ #include <QtGui/QWindow> #include <QtWidgets/QWidget> +#include <numeric> #include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> static const basegfx::B2DPoint aHalfPointOfs(0.5, 0.5); @@ -323,37 +325,67 @@ bool Qt5Graphics::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32* bool Qt5Graphics::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolyLine, double fTransparency, - const basegfx::B2DVector& rLineWidths, + const basegfx::B2DVector& rLineWidth, + const std::vector<double>* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, bool bPixelSnapHairline) { if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + { return true; + } - // short circuit if there is nothing to do - if (0 == rPolyLine.count()) + // MM01 check done for simple reasons + if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0) { return true; } + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength( + nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if (bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing(rPolyLine, // source + *pStroke, // pattern + &aPolyPolygonLine, // traget for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing, just copy + aPolyPolygonLine.append(rPolyLine); + } + // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline - basegfx::B2DPolygon aPolyLine(rPolyLine); - aPolyLine.transform(rObjectToDevice); + aPolyPolygonLine.transform(rObjectToDevice); if (bPixelSnapHairline) { - aPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyLine); + aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); } - const basegfx::B2DVector aLineWidths(rObjectToDevice * rLineWidths); + const basegfx::B2DVector aLineWidth(rObjectToDevice * rLineWidth); // setup poly-polygon path QPainterPath aPath; - AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAliasB2DDraw(), true); + + // MM01 todo - I assume that this is OKAY to be done in one run for Qt5, + // but this NEEDS to be checked/verified + for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAliasB2DDraw(), true); + } Qt5Painter aPainter(*this, false, 255 * (1.0 - fTransparency)); // setup line attributes QPen aPen = aPainter.pen(); - aPen.setWidth(aLineWidths.getX()); + aPen.setWidth(aLineWidth.getX()); switch (eLineJoin) { diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx index e43e75caad2e..684cff1e9bd4 100644 --- a/vcl/quartz/salgdicommon.cxx +++ b/vcl/quartz/salgdicommon.cxx @@ -22,9 +22,11 @@ #include <cassert> #include <cstring> +#include <numeric> #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> #include <osl/endian.h> #include <osl/file.hxx> #include <sal/types.h> @@ -851,15 +853,18 @@ bool AquaSalGraphics::drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolyLine, double fTransparency, - const basegfx::B2DVector& rLineWidths, + const basegfx::B2DVector& rLineWidth, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, bool bPixelSnapHairline) { - // short circuit if there is nothing to do - if(0 == rPolyLine.count()) + // MM01 check done for simple reasons + if(!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0) + { return true; + } #ifdef IOS if( !CheckContext() ) @@ -867,20 +872,40 @@ bool AquaSalGraphics::drawPolyLine( #endif // need to check/handle LineWidth when ObjectToDevice transformation is used - const basegfx::B2DVector aDeviceLineWidths(rObjectToDevice * rLineWidths); - const bool bCorrectLineWidth(aDeviceLineWidths.getX() < 1.0 && rLineWidths.getX() >= 1.0); - const basegfx::B2DVector aLineWidths(bCorrectLineWidth ? rLineWidths : aDeviceLineWidths); + const basegfx::B2DVector aDeviceLineWidth(rObjectToDevice * rLineWidth); + const bool bCorrectLineWidth(aDeviceLineWidth.getX() < 1.0 && rLineWidth.getX() >= 1.0); + const basegfx::B2DVector aLineWidth(bCorrectLineWidth ? rLineWidth : aDeviceLineWidth); // #i101491# Aqua does not support B2DLineJoin::NONE; return false to use // the fallback (own geometry preparation) // #i104886# linejoin-mode and thus the above only applies to "fat" lines - if( (basegfx::B2DLineJoin::NONE == eLineJoin) && (aLineWidths.getX() > 1.3) ) + if( (basegfx::B2DLineJoin::NONE == eLineJoin) && (aLineWidth.getX() > 1.3) ) return false; + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if(bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing( + rPolyLine, // source + *pStroke, // pattern + &aPolyPolygonLine, // traget for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing, just copy + aPolyPolygonLine.append(rPolyLine); + } + // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline - basegfx::B2DPolygon aPolyLine(rPolyLine); - aPolyLine.transform(rObjectToDevice); - if(bPixelSnapHairline) { aPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyLine); } + aPolyPolygonLine.transform(rObjectToDevice); + if(bPixelSnapHairline) { aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); } // setup line attributes CGLineJoin aCGLineJoin = kCGLineJoinMiter; @@ -918,12 +943,19 @@ bool AquaSalGraphics::drawPolyLine( // setup poly-polygon path CGMutablePathRef xPath = CGPathCreateMutable(); SAL_INFO( "vcl.cg", "CGPathCreateMutable() = " << xPath ); - AddPolygonToPath( - xPath, - aPolyLine, - aPolyLine.isClosed(), - !getAntiAliasB2DDraw(), - true); + + // MM01 todo - I assume that this is OKAY to be done in one run for quartz + // but this NEEDS to be checked/verified + for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + AddPolygonToPath( + xPath, + aPolyLine, + aPolyLine.isClosed(), + !getAntiAliasB2DDraw(), + true); + } const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); SAL_INFO( "vcl.cg", "CGPathGetBoundingBox(" << xPath << ") = " << aRefreshRect ); @@ -943,7 +975,7 @@ bool AquaSalGraphics::drawPolyLine( CGContextSetAlpha( mrContext, 1.0 - fTransparency ); CGContextSetLineJoin( mrContext, aCGLineJoin ); CGContextSetLineCap( mrContext, aCGLineCap ); - CGContextSetLineWidth( mrContext, aLineWidths.getX() ); + CGContextSetLineWidth( mrContext, aLineWidth.getX() ); CGContextSetMiterLimit(mrContext, fCGMiterLimit); SAL_INFO( "vcl.cg", "CGContextDrawPath(" << mrContext << ",kCGPathStroke)" ); CGContextDrawPath( mrContext, kCGPathStroke ); diff --git a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx index 8256b0529dd7..bd494866a21f 100644..100755 --- a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx +++ b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx @@ -300,6 +300,7 @@ void drawFromDrawCommands(gfx::DrawRoot const& rDrawRoot, SalGraphics& rGraphics rGraphics.DrawPolyLine( basegfx::B2DHomMatrix(), aB2DPolygon, 1.0 - rRectangle.mnOpacity, basegfx::B2DVector(rRectangle.mnStrokeWidth, rRectangle.mnStrokeWidth), + nullptr, // MM01 basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false, nullptr); } @@ -347,6 +348,7 @@ void drawFromDrawCommands(gfx::DrawRoot const& rDrawRoot, SalGraphics& rGraphics rGraphics.DrawPolyLine( basegfx::B2DHomMatrix(), rPolygon, 1.0 - rPath.mnOpacity, basegfx::B2DVector(rPath.mnStrokeWidth, rPath.mnStrokeWidth), + nullptr, // MM01 basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false, nullptr); } @@ -389,6 +391,7 @@ void munchDrawCommands(std::vector<std::shared_ptr<WidgetDrawAction>> const& rDr rGraphics.DrawPolyLine( basegfx::B2DHomMatrix(), aB2DPolygon, 0.0f, basegfx::B2DVector(rWidgetDraw.mnStrokeWidth, rWidgetDraw.mnStrokeWidth), + nullptr, // MM01 basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false, nullptr); } break; @@ -412,6 +415,7 @@ void munchDrawCommands(std::vector<std::shared_ptr<WidgetDrawAction>> const& rDr rGraphics.DrawPolyLine( basegfx::B2DHomMatrix(), aB2DPolygon, 0.0f, basegfx::B2DVector(rWidgetDraw.mnStrokeWidth, rWidgetDraw.mnStrokeWidth), + nullptr, // MM01 basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false, nullptr); } break; diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index 61c510a363d8..114e4051ec24 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -573,6 +573,7 @@ bool SalGraphics::DrawPolyLine( const basegfx::B2DPolygon& i_rPolygon, double i_fTransparency, const basegfx::B2DVector& i_rLineWidth, + const std::vector< double >* i_pStroke, // MM01 basegfx::B2DLineJoin i_eLineJoin, css::drawing::LineCap i_eLineCap, double i_fMiterMinimumAngle, @@ -601,6 +602,7 @@ bool SalGraphics::DrawPolyLine( i_rPolygon, i_fTransparency, i_rLineWidth, + i_pStroke, // MM01 i_eLineJoin, i_eLineCap, i_fMiterMinimumAngle, @@ -628,6 +630,7 @@ bool SalGraphics::DrawPolyLine( i_rPolygon, i_fTransparency, i_rLineWidth, + i_pStroke, // MM01 i_eLineJoin, i_eLineCap, i_fMiterMinimumAngle, @@ -642,6 +645,7 @@ bool SalGraphics::DrawPolyLine( i_rPolygon, i_fTransparency, i_rLineWidth, + i_pStroke, // MM01 i_eLineJoin, i_eLineCap, i_fMiterMinimumAngle, diff --git a/vcl/source/outdev/line.cxx b/vcl/source/outdev/line.cxx index ef7cb30ef6ba..a6a23026aa94 100644 --- a/vcl/source/outdev/line.cxx +++ b/vcl/source/outdev/line.cxx @@ -133,6 +133,7 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt ) aB2DPolyLine, 0.0, aB2DLineWidth, + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default @@ -244,6 +245,7 @@ void OutputDevice::drawLine( basegfx::B2DPolyPolygon aLinePolyPolygon, const Lin rB2DPolygon, 0.0, basegfx::B2DVector(1.0,1.0), + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx index aacbe00df924..8aeda1d0c1e5 100644 --- a/vcl/source/outdev/polygon.cxx +++ b/vcl/source/outdev/polygon.cxx @@ -101,6 +101,7 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly ) rPolygon, 0.0, aB2DLineWidth, + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default @@ -219,6 +220,7 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly ) aB2DPolygon, 0.0, aB2DLineWidth, + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default @@ -329,6 +331,7 @@ void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP rPolygon, 0.0, aB2DLineWidth, + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default diff --git a/vcl/source/outdev/polyline.cxx b/vcl/source/outdev/polyline.cxx index a1b63fe494dd..997f5383aa12 100644 --- a/vcl/source/outdev/polyline.cxx +++ b/vcl/source/outdev/polyline.cxx @@ -76,6 +76,7 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly ) aB2DPolyLine, 0.0, aB2DLineWidth, + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0) /*default fMiterMinimumAngle, not used*/, @@ -179,6 +180,7 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon, rB2DPolygon, fLineWidth, 0.0, + nullptr, // MM01 eLineJoin, eLineCap, fMiterMinimumAngle)) @@ -235,6 +237,7 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon, rPolygon, 0.0, 0.0, + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0) /*default, not used*/, @@ -306,6 +309,7 @@ bool OutputDevice::DrawPolyLineDirect( const basegfx::B2DPolygon& rB2DPolygon, double fLineWidth, double fTransparency, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, @@ -350,6 +354,7 @@ bool OutputDevice::DrawPolyLineDirect( rB2DPolygon, fTransparency, aB2DLineWidth, + pStroke, // MM01 eLineJoin, eLineCap, fMiterMinimumAngle, diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx index fdb3115b2812..764d13fc80d8 100644 --- a/vcl/source/outdev/transparent.cxx +++ b/vcl/source/outdev/transparent.cxx @@ -278,6 +278,7 @@ void OutputDevice::DrawTransparent( rPolygon, fTransparency, aHairlineWidth, + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default @@ -400,6 +401,7 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly rPolygon, fTransparency, aLineWidths, + nullptr, // MM01 basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx index e0a4879ff6fb..62c29fb593bd 100644 --- a/vcl/unx/generic/gdi/gdiimpl.cxx +++ b/vcl/unx/generic/gdi/gdiimpl.cxx @@ -18,6 +18,8 @@ */ #include <memory> +#include <numeric> + #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/extensions/Xrender.h> @@ -1656,6 +1658,7 @@ private: basegfx::B2DLineJoin meJoin; css::drawing::LineCap meCap; double mfMiterMinimumAngle; + std::vector< double > maStroke; public: SystemDependentData_Triangulation( @@ -1664,13 +1667,16 @@ public: const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eJoin, css::drawing::LineCap eCap, - double fMiterMinimumAngle); + double fMiterMinimumAngle, + const std::vector< double >* pStroke); // MM01 + // read access const basegfx::triangulator::B2DTriangleVector& getTriangles() const { return maTriangles; } const basegfx::B2DVector& getLineWidth() const { return maLineWidth; } const basegfx::B2DLineJoin& getJoin() const { return meJoin; } const css::drawing::LineCap& getCap() const { return meCap; } double getMiterMinimumAngle() const { return mfMiterMinimumAngle; } + const std::vector< double >& getStroke() const { return maStroke; } virtual sal_Int64 estimateUsageInBytes() const override; }; @@ -1681,14 +1687,20 @@ SystemDependentData_Triangulation::SystemDependentData_Triangulation( const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eJoin, css::drawing::LineCap eCap, - double fMiterMinimumAngle) + double fMiterMinimumAngle, + const std::vector< double >* pStroke) : basegfx::SystemDependentData(rSystemDependentDataManager), maTriangles(rTriangles), maLineWidth(rLineWidth), meJoin(eJoin), meCap(eCap), - mfMiterMinimumAngle(fMiterMinimumAngle) + mfMiterMinimumAngle(fMiterMinimumAngle), + maStroke() { + if(nullptr != pStroke) + { + maStroke = *pStroke; + } } sal_Int64 SystemDependentData_Triangulation::estimateUsageInBytes() const @@ -1708,6 +1720,7 @@ bool X11SalGraphicsImpl::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidth, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, @@ -1725,7 +1738,6 @@ bool X11SalGraphicsImpl::drawPolyLine( const basegfx::B2DVector aDeviceLineWidths(bObjectToDeviceIsIdentity ? rLineWidth : rObjectToDevice * rLineWidth); const bool bCorrectLineWidth(!bObjectToDeviceIsIdentity && aDeviceLineWidths.getX() < 1.0 && aLineWidth.getX() >= 1.0); basegfx::B2DHomMatrix aObjectToDeviceInv; - basegfx::B2DPolygon aPolygon(rPolygon); if(bCorrectLineWidth) { @@ -1743,6 +1755,25 @@ bool X11SalGraphicsImpl::drawPolyLine( std::shared_ptr<SystemDependentData_Triangulation> pSystemDependentData_Triangulation( rPolygon.getSystemDependentData<SystemDependentData_Triangulation>()); + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + + if(pSystemDependentData_Triangulation) + { + // MM01 - check on stroke change. Used against not used, or if oth used, + // equal or different? Triangulation geometry creation depends heavily + // on stroke, independent of being transformation independent + const bool bStrokeWasUsed(!pSystemDependentData_Triangulation->getStroke().empty()); + + if(bStrokeWasUsed != bStrokeUsed + || (bStrokeUsed && *pStroke != pSystemDependentData_Triangulation->getStroke())) + { + // data invalid, forget + pSystemDependentData_Triangulation.reset(); + } + } + if(pSystemDependentData_Triangulation) { // check data validity (I) @@ -1779,15 +1810,36 @@ bool X11SalGraphicsImpl::drawPolyLine( if(!pSystemDependentData_Triangulation) { + // MM01 need to do line dashing as fallback stuff here now + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if(bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing( + rPolygon, // source + *pStroke, // pattern + &aPolyPolygonLine, // traget for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing, just copy + aPolyPolygonLine.append(rPolygon); + } + // try to create data if(bPixelSnapHairline) { + // Do NOT transform, but keep device-independent. To + // do so, transform to device for snap, but back again after if(!bObjectToDeviceIsIdentity) { - aPolygon.transform(rObjectToDevice); + aPolyPolygonLine.transform(rObjectToDevice); } - aPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolygon); + aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); if(!bObjectToDeviceIsIdentity) { @@ -1797,21 +1849,30 @@ bool X11SalGraphicsImpl::drawPolyLine( aObjectToDeviceInv.invert(); } - aPolygon.transform(aObjectToDeviceInv); + aPolyPolygonLine.transform(aObjectToDeviceInv); } } basegfx::triangulator::B2DTriangleVector aTriangles; - const basegfx::B2DPolyPolygon aAreaPolyPoly( + + // MM01 checked/verified for X11 (linux) + for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + // MM01 upps - commit 51b5b93092d6231615de470c62494c24e54828a1 removed + // this *central* geometry-creating lines (!) probably due to aAreaPolyPoly + // *not* being used - that's true, but the work is inside of filling + // aTriangles data (!) basegfx::utils::createAreaGeometry( - aPolygon, + aPolyLine, 0.5 * aLineWidth.getX(), eLineJoin, eLineCap, basegfx::deg2rad(12.5), 0.4, fMiterMinimumAngle, - &aTriangles)); + &aTriangles); // CAUTION! This is *needed* since it creates the data! + } if(!aTriangles.empty()) { @@ -1824,7 +1885,8 @@ bool X11SalGraphicsImpl::drawPolyLine( aLineWidth, eLineJoin, eLineCap, - fMiterMinimumAngle); + fMiterMinimumAngle, + pStroke); } } diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx index 282b9a29a8d9..222bc6c7a3c1 100644 --- a/vcl/unx/generic/gdi/gdiimpl.hxx +++ b/vcl/unx/generic/gdi/gdiimpl.hxx @@ -173,6 +173,7 @@ public: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index 1af613902663..fd3c926b95a5 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -706,6 +706,7 @@ bool X11SalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidth, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, @@ -742,6 +743,7 @@ bool X11SalGraphics::drawPolyLine( rPolygon, fTransparency, rLineWidth, + pStroke, // MM01 eLineJoin, eLineCap, fMiterMinimumAngle, @@ -761,6 +763,7 @@ bool X11SalGraphics::drawPolyLine( rPolygon, fTransparency, rLineWidth, + pStroke, // MM01 eLineJoin, eLineCap, fMiterMinimumAngle, diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx index e40b9fd5cc82..7a5df6b3e262 100644 --- a/vcl/unx/generic/print/genpspgraphics.cxx +++ b/vcl/unx/generic/print/genpspgraphics.cxx @@ -419,6 +419,7 @@ bool GenPspGraphics::drawPolyLine( const basegfx::B2DPolygon&, double /*fTransparency*/, const basegfx::B2DVector& /*rLineWidths*/, + const std::vector< double >* /*pStroke*/, // MM01 basegfx::B2DLineJoin /*eJoin*/, css::drawing::LineCap /*eLineCap*/, double /*fMiterMinimumAngle*/, diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index 434cdcbac8e4..26f972919ff4 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -17,6 +17,11 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <sal/config.h> + +#include <memory> +#include <numeric> + #include <svsys.h> #include "gdiimpl.hxx" @@ -1957,18 +1962,19 @@ private: // all other values the triangulation is based on and // need to be compared with to check for data validity bool mbNoLineJoin; + std::vector< double > maStroke; public: SystemDependentData_GraphicsPath( basegfx::SystemDependentDataManager& rSystemDependentDataManager, std::shared_ptr<Gdiplus::GraphicsPath>& rpGraphicsPath, - bool bNoLineJoin); + bool bNoLineJoin, + const std::vector< double >* pStroke); // MM01 - // read access to Gdiplus::GraphicsPath + // read access std::shared_ptr<Gdiplus::GraphicsPath>& getGraphicsPath() { return mpGraphicsPath; } - - // other data-validity access bool getNoLineJoin() const { return mbNoLineJoin; } + const std::vector< double >& getStroke() const { return maStroke; } virtual sal_Int64 estimateUsageInBytes() const override; }; @@ -1976,11 +1982,17 @@ public: SystemDependentData_GraphicsPath::SystemDependentData_GraphicsPath( basegfx::SystemDependentDataManager& rSystemDependentDataManager, std::shared_ptr<Gdiplus::GraphicsPath>& rpGraphicsPath, - bool bNoLineJoin) + bool bNoLineJoin, + const std::vector< double >* pStroke) : basegfx::SystemDependentData(rSystemDependentDataManager), mpGraphicsPath(rpGraphicsPath), - mbNoLineJoin(bNoLineJoin) + mbNoLineJoin(bNoLineJoin), + maStroke() { + if(nullptr != pStroke) + { + maStroke = *pStroke; + } } sal_Int64 SystemDependentData_GraphicsPath::estimateUsageInBytes() const @@ -2104,7 +2116,8 @@ bool WinSalGraphicsImpl::drawPolyPolygon( rPolyPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>( ImplGetSystemDependentDataManager(), pGraphicsPath, - false); + false, + nullptr); } if(mrParent.getAntiAliasB2DDraw()) @@ -2164,12 +2177,14 @@ bool WinSalGraphicsImpl::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, bool bPixelSnapHairline) { - if(!mbPen || 0 == rPolygon.count()) + // MM01 check done for simple reasons + if(!mbPen || !rPolygon.count() || fTransparency < 0.0 || fTransparency > 1.0) { return true; } @@ -2261,6 +2276,25 @@ bool WinSalGraphicsImpl::drawPolyLine( std::shared_ptr<SystemDependentData_GraphicsPath> pSystemDependentData_GraphicsPath( rPolygon.getSystemDependentData<SystemDependentData_GraphicsPath>()); + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + + if(pSystemDependentData_GraphicsPath) + { + // MM01 - check on stroke change. Used against not used, or if oth used, + // equal or different? Triangulation geometry creation depends heavily + // on stroke, independent of being transformation independent + const bool bStrokeWasUsed(!pSystemDependentData_GraphicsPath->getStroke().empty()); + + if(bStrokeWasUsed != bStrokeUsed + || (bStrokeUsed && *pStroke != pSystemDependentData_GraphicsPath->getStroke())) + { + // data invalid, forget + pSystemDependentData_GraphicsPath.reset(); + } + } + if(pSystemDependentData_GraphicsPath) { // check data validity @@ -2282,17 +2316,47 @@ bool WinSalGraphicsImpl::drawPolyLine( // fill data of buffered data pGraphicsPath.reset(new Gdiplus::GraphicsPath()); - impAddB2DPolygonToGDIPlusGraphicsPathReal( - *pGraphicsPath, - rPolygon, - rObjectToDevice, - bNoLineJoin, - bPixelSnapHairline); - - if(rPolygon.isClosed() && !bNoLineJoin) + if(bStrokeUsed) { - // #i101491# needed to create the correct line joins - pGraphicsPath->CloseFigure(); + // MM01 need to do line dashing as fallback stuff here now + basegfx::B2DPolyPolygon aPolyPolygonLine; + + // apply LineStyle + basegfx::utils::applyLineDashing( + rPolygon, // source + *pStroke, // pattern + &aPolyPolygonLine, // traget for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + + // MM01 checked/verified, ok + for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + pGraphicsPath->StartFigure(); + impAddB2DPolygonToGDIPlusGraphicsPathReal( + *pGraphicsPath, + aPolyLine, + rObjectToDevice, + bNoLineJoin, + bPixelSnapHairline); + } + } + else + { + // no line dashing, just copy + impAddB2DPolygonToGDIPlusGraphicsPathReal( + *pGraphicsPath, + rPolygon, + rObjectToDevice, + bNoLineJoin, + bPixelSnapHairline); + + if(rPolygon.isClosed() && !bNoLineJoin) + { + // #i101491# needed to create the correct line joins + pGraphicsPath->CloseFigure(); + } } // add to buffering mechanism @@ -2301,7 +2365,8 @@ bool WinSalGraphicsImpl::drawPolyLine( rPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>( ImplGetSystemDependentDataManager(), pGraphicsPath, - bNoLineJoin); + bNoLineJoin, + pStroke); } } diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx index 54d75bd9291c..086d7312b695 100644 --- a/vcl/win/gdi/gdiimpl.hxx +++ b/vcl/win/gdi/gdiimpl.hxx @@ -117,6 +117,7 @@ public: const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, diff --git a/vcl/win/gdi/salgdi_gdiplus.cxx b/vcl/win/gdi/salgdi_gdiplus.cxx index 99c7d0e506e9..ce2f2cc69c20 100644 --- a/vcl/win/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/gdi/salgdi_gdiplus.cxx @@ -42,6 +42,7 @@ bool WinSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidths, + const std::vector< double >* pStroke, // MM01 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, double fMiterMinimumAngle, @@ -52,6 +53,7 @@ bool WinSalGraphics::drawPolyLine( rPolygon, fTransparency, rLineWidths, + pStroke, // MM01 eLineJoin, eLineCap, fMiterMinimumAngle, |