vcl/headless/CairoCommon.cxx | 14 vcl/headless/SvpGraphicsBackend.cxx | 16 - vcl/inc/headless/CairoCommon.hxx | 6 vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx | 10 vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx | 4 vcl/unx/generic/gdi/gdiimpl.cxx | 351 ------------------------ vcl/unx/generic/gdi/gdiimpl.hxx | 17 - 7 files changed, 36 insertions(+), 382 deletions(-)
New commits: commit 498f0208f55a5b9ce8a130c940ddfcb9c36d6ff9 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Fri Jan 6 09:04:41 2023 +0000 Commit: Caolán McNamara <caol...@redhat.com> CommitDate: Fri Jan 6 14:49:31 2023 +0000 move drawPolyLine into CairoCommon and reuse from X11CairoSalGraphicsImpl Change-Id: I141b12c99825c67e4698d53633a1fa720cc487be Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145136 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx index 0779cb65c564..b0c7b505f7cc 100644 --- a/vcl/headless/CairoCommon.cxx +++ b/vcl/headless/CairoCommon.cxx @@ -791,6 +791,20 @@ bool CairoCommon::drawPolyPolygon(cairo_t* cr, basegfx::B2DRange* pExtents, return true; } +void CairoCommon::drawPolyLine(cairo_t* cr, basegfx::B2DRange* pExtents, const Color& rLineColor, + bool bAntiAlias, sal_uInt32 nPoints, const Point* pPtAry) +{ + basegfx::B2DPolygon aPoly; + aPoly.append(basegfx::B2DPoint(pPtAry->getX(), pPtAry->getY()), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].getX(), pPtAry[i].getY())); + aPoly.setClosed(false); + + drawPolyLine(cr, pExtents, rLineColor, bAntiAlias, basegfx::B2DHomMatrix(), aPoly, 0.0, 1.0, + nullptr, basegfx::B2DLineJoin::Miter, css::drawing::LineCap_BUTT, + basegfx::deg2rad(15.0) /*default*/, false); +} + bool CairoCommon::drawPolyLine(cairo_t* cr, basegfx::B2DRange* pExtents, const Color& rLineColor, bool bAntiAlias, const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolyLine, double fTransparency, diff --git a/vcl/headless/SvpGraphicsBackend.cxx b/vcl/headless/SvpGraphicsBackend.cxx index bf79416d88b7..134c9fc221e0 100644 --- a/vcl/headless/SvpGraphicsBackend.cxx +++ b/vcl/headless/SvpGraphicsBackend.cxx @@ -209,16 +209,14 @@ void SvpGraphicsBackend::implDrawRect(double nX, double nY, double nWidth, doubl void SvpGraphicsBackend::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry) { - basegfx::B2DPolygon aPoly; - aPoly.append(basegfx::B2DPoint(pPtAry->getX(), pPtAry->getY()), nPoints); - for (sal_uInt32 i = 1; i < nPoints; ++i) - aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].getX(), pPtAry[i].getY())); - aPoly.setClosed(false); + cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias()); + basegfx::B2DRange aExtents; + m_rCairoCommon.clipRegion(cr); - drawPolyLine(basegfx::B2DHomMatrix(), aPoly, 0.0, 1.0, - nullptr, // MM01 - basegfx::B2DLineJoin::Miter, css::drawing::LineCap_BUTT, - basegfx::deg2rad(15.0) /*default*/, false); + CairoCommon::drawPolyLine(cr, &aExtents, *m_rCairoCommon.m_oLineColor, getAntiAlias(), nPoints, + pPtAry); + + m_rCairoCommon.releaseCairoContext(cr, false, aExtents); } void SvpGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry) diff --git a/vcl/inc/headless/CairoCommon.hxx b/vcl/inc/headless/CairoCommon.hxx index 7489ecaad969..75aec44a4ec7 100644 --- a/vcl/inc/headless/CairoCommon.hxx +++ b/vcl/inc/headless/CairoCommon.hxx @@ -173,9 +173,9 @@ struct VCL_DLLPUBLIC CairoCommon const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolyPolygon&, double fTransparency); - // need this static version of ::drawPolyLine for usage from - // vcl/unx/generic/gdi/salgdi.cxx. It gets wrapped by - // ::drawPolyLine with some added parameters (see there) + static void drawPolyLine(cairo_t* cr, basegfx::B2DRange* pExtents, const Color& rLineColor, + bool bAntiAlias, sal_uInt32 nPoints, const Point* pPtAry); + static bool drawPolyLine(cairo_t* cr, basegfx::B2DRange* pExtents, const Color& rLineColor, bool bAntiAlias, const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolyLine, double fTransparency, diff --git a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx index 60cbf1230400..b1afbc25350f 100644 --- a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx +++ b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx @@ -93,6 +93,16 @@ void X11CairoSalGraphicsImpl::drawLine(tools::Long nX1, tools::Long nY1, tools:: X11Common::releaseCairoContext(cr); } +void X11CairoSalGraphicsImpl::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry) +{ + cairo_t* cr = mrX11Common.getCairoContext(mrParent.GetGeometryProvider()); + clipRegion(cr); + + CairoCommon::drawPolyLine(cr, nullptr, *moPenColor, getAntiAlias(), nPoints, pPtAry); + + X11Common::releaseCairoContext(cr); +} + bool X11CairoSalGraphicsImpl::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolyLine, double fTransparency, double fLineWidth, diff --git a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx index a1b5b6d475e7..46b4c74bcc98 100644 --- a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx +++ b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx @@ -32,8 +32,6 @@ private: std::optional<Color> moPenColor; std::optional<Color> moFillColor; - using X11SalGraphicsImpl::drawPolyLine; - public: X11CairoSalGraphicsImpl(X11SalGraphics& rParent, X11Common& rX11Common); @@ -88,6 +86,8 @@ public: const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) override; + void drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry) override; + bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolygon, double fTransparency, double fLineWidth, const std::vector<double>* pStroke, basegfx::B2DLineJoin eLineJoin, diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx index 2afee55b9a99..73d49949e2af 100644 --- a/vcl/unx/generic/gdi/gdiimpl.cxx +++ b/vcl/unx/generic/gdi/gdiimpl.cxx @@ -1119,16 +1119,6 @@ void X11SalGraphicsImpl::drawRect( tools::Long nX, tools::Long nY, tools::Long n nX, nY, nDX-1, nDY-1 ); } -void X11SalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const Point *pPtAry ) -{ - if( moPenColor ) - { - SalPolyLine Points( nPoints, pPtAry ); - - DrawLines( nPoints, Points, SelectPen(), false ); - } -} - void X11SalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const Point* pPtAry ) { if( nPoints == 0 ) @@ -1278,347 +1268,6 @@ tools::Long X11SalGraphicsImpl::GetGraphicsHeight() const return 0; } -bool X11SalGraphicsImpl::drawFilledTriangles( - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::triangulator::B2DTriangleVector& rTriangles, - double fTransparency) -{ - if(rTriangles.empty()) - return true; - - Picture aDstPic = GetXRenderPicture(); - // check xrender support for this drawable - if( !aDstPic ) - { - return false; - } - - // prepare transformation for ObjectToDevice coordinate system - basegfx::B2DHomMatrix aObjectToDevice = basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5) * rObjectToDevice; - - // convert the Triangles into XRender-Triangles - std::vector<XTriangle> aTriVector(rTriangles.size()); - sal_uInt32 nIndex(0); - - for(const auto& rCandidate : rTriangles) - { - const basegfx::B2DPoint aP1(aObjectToDevice * rCandidate.getA()); - const basegfx::B2DPoint aP2(aObjectToDevice * rCandidate.getB()); - const basegfx::B2DPoint aP3(aObjectToDevice * rCandidate.getC()); - XTriangle& rTri(aTriVector[nIndex++]); - - rTri.p1.x = XDoubleToFixed(aP1.getX()); - rTri.p1.y = XDoubleToFixed(aP1.getY()); - - rTri.p2.x = XDoubleToFixed(aP2.getX()); - rTri.p2.y = XDoubleToFixed(aP2.getY()); - - rTri.p3.x = XDoubleToFixed(aP3.getX()); - rTri.p3.y = XDoubleToFixed(aP3.getY()); - } - - // get xrender Picture for polygon foreground - // TODO: cache it like the target picture which uses GetXRenderPicture() - XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); - SalDisplay::RenderEntry& rEntry = mrParent.GetDisplay()->GetRenderEntries( mrParent.m_nXScreen )[ 32 ]; - if( !rEntry.m_aPicture ) - { - Display* pXDisplay = mrParent.GetXDisplay(); - - rEntry.m_aPixmap = limitXCreatePixmap( pXDisplay, mrParent.GetDrawable(), 1, 1, 32 ); - XRenderPictureAttributes aAttr; - aAttr.repeat = int(true); - - XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 ); - rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr ); - } - - // set polygon foreground color and opacity - XRenderColor aRenderColor = GetXRenderColor( *moBrushColor , fTransparency ); - rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 ); - - // set clipping - // TODO: move into GetXRenderPicture? - if( mrParent.mpClipRegion && !XEmptyRegion( mrParent.mpClipRegion ) ) - rRenderPeer.SetPictureClipRegion( aDstPic, mrParent.mpClipRegion ); - - // render the trapezoids - const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8(); - rRenderPeer.CompositeTriangles( PictOpOver, - rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, aTriVector.data(), aTriVector.size() ); - - return true; -} - -namespace { - -class SystemDependentData_Triangulation : public basegfx::SystemDependentData -{ -private: - // the triangulation itself - basegfx::triangulator::B2DTriangleVector maTriangles; - - // all other values the triangulation is based on and - // need to be compared with to check for data validity - double mfLineWidth; - basegfx::B2DLineJoin meJoin; - css::drawing::LineCap meCap; - double mfMiterMinimumAngle; - std::vector< double > maStroke; - -public: - SystemDependentData_Triangulation( - basegfx::triangulator::B2DTriangleVector&& rTriangles, - double fLineWidth, - basegfx::B2DLineJoin eJoin, - css::drawing::LineCap eCap, - double fMiterMinimumAngle, - const std::vector< double >* pStroke); // MM01 - - // read access - const basegfx::triangulator::B2DTriangleVector& getTriangles() const { return maTriangles; } - double getLineWidth() const { return mfLineWidth; } - 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; -}; - -} - -SystemDependentData_Triangulation::SystemDependentData_Triangulation( - basegfx::triangulator::B2DTriangleVector&& rTriangles, - double fLineWidth, - basegfx::B2DLineJoin eJoin, - css::drawing::LineCap eCap, - double fMiterMinimumAngle, - const std::vector< double >* pStroke) -: basegfx::SystemDependentData(Application::GetSystemDependentDataManager()), - maTriangles(std::move(rTriangles)), - mfLineWidth(fLineWidth), - meJoin(eJoin), - meCap(eCap), - mfMiterMinimumAngle(fMiterMinimumAngle) -{ - if(nullptr != pStroke) - { - maStroke = *pStroke; - } -} - -sal_Int64 SystemDependentData_Triangulation::estimateUsageInBytes() const -{ - sal_Int64 nRetval(0); - - if(!maTriangles.empty()) - { - nRetval = maTriangles.size() * sizeof(basegfx::triangulator::B2DTriangle); - } - - return nRetval; -} - -bool X11SalGraphicsImpl::drawPolyLine( - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolygon& rPolygon, - double fTransparency, - double fLineWidth, - 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 == rPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0) - { - return true; - } - - // need to check/handle LineWidth when ObjectToDevice transformation is used - const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity()); - basegfx::B2DHomMatrix aObjectToDeviceInv; - - // 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(fLineWidth == 0) - { - fLineWidth = 1.0; - - if(!bObjectToDeviceIsIdentity) - { - if(aObjectToDeviceInv.isIdentity()) - { - aObjectToDeviceInv = rObjectToDevice; - aObjectToDeviceInv.invert(); - } - - fLineWidth = (aObjectToDeviceInv * basegfx::B2DVector(fLineWidth, 0)).getLength(); - } - } - - // try to access buffered data - 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); - assert(!bStrokeUsed || (bStrokeUsed && pStroke)); - - 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) - if(pSystemDependentData_Triangulation->getJoin() != eLineJoin - || pSystemDependentData_Triangulation->getCap() != eLineCap - || pSystemDependentData_Triangulation->getMiterMinimumAngle() != fMiterMinimumAngle) - { - // data invalid, forget - pSystemDependentData_Triangulation.reset(); - } - } - - if(pSystemDependentData_Triangulation) - { - // check data validity (II) - if(pSystemDependentData_Triangulation->getLineWidth() != fLineWidth) - { - // sometimes small inconsistencies, use a percentage tolerance - const double fFactor(basegfx::fTools::equalZero(fLineWidth) - ? 0.0 - : fabs(1.0 - (pSystemDependentData_Triangulation->getLineWidth() / fLineWidth))); - // compare with 5.0% tolerance - if(basegfx::fTools::more(fFactor, 0.05)) - { - // data invalid, forget - pSystemDependentData_Triangulation.reset(); - } - } - } - - 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, // target 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) - { - aPolyPolygonLine.transform(rObjectToDevice); - } - - aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); - - if(!bObjectToDeviceIsIdentity) - { - if(aObjectToDeviceInv.isIdentity()) - { - aObjectToDeviceInv = rObjectToDevice; - aObjectToDeviceInv.invert(); - } - - aPolyPolygonLine.transform(aObjectToDeviceInv); - } - } - - basegfx::triangulator::B2DTriangleVector aTriangles; - - // 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( - aPolyLine, - 0.5 * fLineWidth, - eLineJoin, - eLineCap, - basegfx::deg2rad(12.5), - 0.4, - fMiterMinimumAngle, - &aTriangles); // CAUTION! This is *needed* since it creates the data! - } - - if(!aTriangles.empty()) - { - // Add to buffering mechanism - // Add all values the triangulation is based off, too, to check for - // validity (see above) - pSystemDependentData_Triangulation = rPolygon.addOrReplaceSystemDependentData<SystemDependentData_Triangulation>( - std::move(aTriangles), - fLineWidth, - eLineJoin, - eLineCap, - fMiterMinimumAngle, - pStroke); - } - } - - if(!pSystemDependentData_Triangulation) - { - return false; - } - - // temporarily adjust brush color to pen color - // since the line is drawn as an area-polygon - const std::optional<Color> aKeepBrushColor = moBrushColor; - moBrushColor = moPenColor; - - // create the area-polygon for the line - const bool bDrawnOk( - drawFilledTriangles( - rObjectToDevice, - pSystemDependentData_Triangulation->getTriangles(), - fTransparency)); - - // restore the original brush GC - moBrushColor = aKeepBrushColor; - return bDrawnOk; -} - std::shared_ptr<SalBitmap> X11SalGraphicsImpl::getBitmap( tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY ) { bool bFakeWindowBG = false; diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx index 4eaf19d2c8ae..4d18ee032602 100644 --- a/vcl/unx/generic/gdi/gdiimpl.hxx +++ b/vcl/unx/generic/gdi/gdiimpl.hxx @@ -91,10 +91,6 @@ private: ); XID GetXRenderPicture(); - bool drawFilledTriangles( - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::triangulator::B2DTriangleVector& rTriangles, - double fTransparency); tools::Long GetGraphicsHeight() const; @@ -151,21 +147,8 @@ public: virtual void drawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) override; - virtual void drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry ) override; - virtual void drawPolygon( sal_uInt32 nPoints, const Point* pPtAry ) override; - virtual bool drawPolyLine( - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolygon&, - double fTransparency, - double fLineWidth, - const std::vector< double >* pStroke, // MM01 - basegfx::B2DLineJoin, - css::drawing::LineCap, - double fMiterMinimumAngle, - bool bPixelSnapHairline) override; - virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const Point* pPtAry,