vcl/headless/CairoCommon.cxx | 249 ++++++++++++++++++++++++++ vcl/headless/SvpGraphicsBackend.cxx | 52 ++++- vcl/headless/svpgdi.cxx | 337 ------------------------------------ vcl/inc/headless/CairoCommon.hxx | 15 + vcl/inc/headless/svpgdi.hxx | 29 --- vcl/unx/generic/gdi/salgdi.cxx | 2 6 files changed, 307 insertions(+), 377 deletions(-)
New commits: commit 8d6343e6b29fc6162d88b25dfa3a165e0d1b063d Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Wed Dec 15 11:56:09 2021 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Sat Jan 1 16:04:27 2022 +0100 vcl: move drawPolyLine (+legacy) to SvpGraphicsBackend Also moves drawPolyLine with cairo context param. to CairoCommon as it is also needed in X11SalGraphics::drawPolyLine. Change-Id: I49b24bc31ecf3f6ab3cebca4eaab351c91564db5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127740 Tested-by: Tomaž Vajngerl <qui...@gmail.com> Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx index 40115a90db1f..7161feb7f29f 100644 --- a/vcl/headless/CairoCommon.cxx +++ b/vcl/headless/CairoCommon.cxx @@ -22,6 +22,10 @@ #include <vcl/BitmapTools.hxx> #include <svdata.hxx> #include <basegfx/utils/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + void dl_cairo_surface_set_device_scale(cairo_surface_t* surface, double x_scale, double y_scale) { #ifdef ANDROID @@ -584,4 +588,249 @@ void CairoCommon::clipRegion(cairo_t* cr, const vcl::Region& rClipRegion) void CairoCommon::clipRegion(cairo_t* cr) { CairoCommon::clipRegion(cr, m_aClipRegion); } +bool CairoCommon::drawPolyLine(cairo_t* cr, basegfx::B2DRange* pExtents, const Color& rLineColor, + bool bAntiAlias, const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, double fTransparency, + double fLineWidth, const std::vector<double>* pStroke, + basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, bool bPixelSnapHairline) +{ + // short circuit if there is nothing to do + if (0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0) + { + return true; + } + + // need to check/handle LineWidth when ObjectToDevice transformation is used + const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity()); + + // tdf#124848 calculate-back logical LineWidth for a hairline + // since this implementation hands over the transformation to + // the graphic sub-system + if (fLineWidth == 0) + { + fLineWidth = 1.0; + + if (!bObjectToDeviceIsIdentity) + { + basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice); + aObjectToDeviceInv.invert(); + fLineWidth = (aObjectToDeviceInv * basegfx::B2DVector(fLineWidth, 0)).getLength(); + } + } + + // PixelOffset used: Need to reflect in linear transformation + cairo_matrix_t aMatrix; + basegfx::B2DHomMatrix aDamageMatrix(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5)); + + if (bObjectToDeviceIsIdentity) + { + // Set PixelOffset as requested + cairo_matrix_init_translate(&aMatrix, 0.5, 0.5); + } + else + { + // Prepare ObjectToDevice transformation. Take PixelOffset for Lines into + // account: Multiply from left to act in DeviceCoordinates + aDamageMatrix = aDamageMatrix * rObjectToDevice; + cairo_matrix_init(&aMatrix, aDamageMatrix.get(0, 0), aDamageMatrix.get(1, 0), + aDamageMatrix.get(0, 1), aDamageMatrix.get(1, 1), aDamageMatrix.get(0, 2), + aDamageMatrix.get(1, 2)); + } + + // set linear transformation + cairo_set_matrix(cr, &aMatrix); + + // setup line attributes + cairo_line_join_t eCairoLineJoin = CAIRO_LINE_JOIN_MITER; + switch (eLineJoin) + { + case basegfx::B2DLineJoin::Bevel: + eCairoLineJoin = CAIRO_LINE_JOIN_BEVEL; + break; + case basegfx::B2DLineJoin::Round: + eCairoLineJoin = CAIRO_LINE_JOIN_ROUND; + break; + case basegfx::B2DLineJoin::NONE: + case basegfx::B2DLineJoin::Miter: + eCairoLineJoin = CAIRO_LINE_JOIN_MITER; + break; + } + + // convert miter minimum angle to miter limit + double fMiterLimit = 1.0 / sin(fMiterMinimumAngle / 2.0); + + // setup cap attribute + cairo_line_cap_t eCairoLineCap(CAIRO_LINE_CAP_BUTT); + + switch (eLineCap) + { + default: // css::drawing::LineCap_BUTT: + { + eCairoLineCap = CAIRO_LINE_CAP_BUTT; + break; + } + case css::drawing::LineCap_ROUND: + { + eCairoLineCap = CAIRO_LINE_CAP_ROUND; + break; + } + case css::drawing::LineCap_SQUARE: + { + eCairoLineCap = CAIRO_LINE_CAP_SQUARE; + break; + } + } + + cairo_set_source_rgba(cr, rLineColor.GetRed() / 255.0, rLineColor.GetGreen() / 255.0, + rLineColor.GetBlue() / 255.0, 1.0 - fTransparency); + + cairo_set_line_join(cr, eCairoLineJoin); + cairo_set_line_cap(cr, eCairoLineCap); + cairo_set_line_width(cr, fLineWidth); + cairo_set_miter_limit(cr, fMiterLimit); + + // try to access buffered data + std::shared_ptr<SystemDependentData_CairoPath> pSystemDependentData_CairoPath( + rPolyLine.getSystemDependentData<SystemDependentData_CairoPath>()); + + // 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)); + + // MM01 decide if to stroke directly + static const bool bDoDirectCairoStroke(true); + + // MM01 activate to stroke directly + if (bDoDirectCairoStroke && bStrokeUsed) + { + cairo_set_dash(cr, pStroke->data(), pStroke->size(), 0.0); + } + + if (!bDoDirectCairoStroke && pSystemDependentData_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 (bStrokeWasUsed != bStrokeUsed + || (bStrokeUsed && *pStroke != pSystemDependentData_CairoPath->getStroke())) + { + // data invalid, forget + pSystemDependentData_CairoPath.reset(); + } + } + + // check for basegfx::B2DLineJoin::NONE to react accordingly + const bool bNoJoin( + (basegfx::B2DLineJoin::NONE == eLineJoin && basegfx::fTools::more(fLineWidth, 0.0))); + + if (pSystemDependentData_CairoPath) + { + // check data validity + if (nullptr == pSystemDependentData_CairoPath->getCairoPath() + || pSystemDependentData_CairoPath->getNoJoin() != bNoJoin + || pSystemDependentData_CairoPath->getAntiAlias() != bAntiAlias + || bPixelSnapHairline /*tdf#124700*/) + { + // data invalid, forget + pSystemDependentData_CairoPath.reset(); + } + } + + if (pSystemDependentData_CairoPath) + { + // re-use data + cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath()); + } + else + { + // create data + size_t nSizeMeasure(0); + + // MM01 need to do line dashing as fallback stuff here now + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if (!bDoDirectCairoStroke && bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing(rPolyLine, // source + *pStroke, // pattern + &aPolyPolygonLine, // target for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing or direct stroke, just copy + aPolyPolygonLine.append(rPolyLine); + } + + // MM01 checked/verified for Cairo + for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + + if (!bNoJoin) + { + // PixelOffset now reflected in linear transformation used + nSizeMeasure + += AddPolygonToPath(cr, aPolyLine, + rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset + !bAntiAlias, 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)); + + 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 + nSizeMeasure += AddPolygonToPath( + cr, aEdge, + rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset + !bAntiAlias, bPixelSnapHairline); + + // prepare next step + aEdge.setB2DPoint(0, aEdge.getB2DPoint(1)); + } + } + } + + // copy and add to buffering mechanism + if (!bPixelSnapHairline /*tdf#124700*/) + { + pSystemDependentData_CairoPath + = rPolyLine.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>( + ImplGetSystemDependentDataManager(), nSizeMeasure, cr, bNoJoin, bAntiAlias, + pStroke); + } + } + + // extract extents + if (pExtents) + { + *pExtents = getClippedStrokeDamage(cr); + // transform also extents (ranges) of damage so they can be correctly redrawn + pExtents->transform(aDamageMatrix); + } + + // draw and consume + cairo_stroke(cr); + + return true; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/SvpGraphicsBackend.cxx b/vcl/headless/SvpGraphicsBackend.cxx index f19749196cab..e955790bd247 100644 --- a/vcl/headless/SvpGraphicsBackend.cxx +++ b/vcl/headless/SvpGraphicsBackend.cxx @@ -187,7 +187,19 @@ void SvpGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long nW m_rCairoCommon.m_aLineColor = aOrigLineColor; } -void SvpGraphicsBackend::drawPolyLine(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/) {} +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); + + drawPolyLine(basegfx::B2DHomMatrix(), aPoly, 0.0, 1.0, + nullptr, // MM01 + basegfx::B2DLineJoin::Miter, css::drawing::LineCap_BUTT, + basegfx::deg2rad(15.0) /*default*/, false); +} void SvpGraphicsBackend::drawPolygon(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/) {} @@ -281,15 +293,37 @@ bool SvpGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToD return true; } -bool SvpGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& /*rObjectToDevice*/, - const basegfx::B2DPolygon& /*rPolyLine*/, - double /*fTransparency*/, double /*fLineWidth*/, - const std::vector<double>* /*pStroke*/, - basegfx::B2DLineJoin /*eLineJoin*/, - css::drawing::LineCap /*eLineCap*/, - double /*fMiterMinimumAngle*/, bool /*bPixelSnapHairline*/) +bool SvpGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, double fTransparency, + double fLineWidth, const std::vector<double>* pStroke, + basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, double fMiterMinimumAngle, + bool bPixelSnapHairline) { - return false; + // short circuit if there is nothing to do + if (0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0) + { + return true; + } + + // Wrap call to static version of ::drawPolyLine by + // preparing/getting some local data and parameters + // due to usage in vcl/unx/generic/gdi/salgdi.cxx. + // This is mainly about extended handling of extents + // and the way destruction of CairoContext is handled + // due to current XOR stuff + cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias()); + basegfx::B2DRange aExtents; + m_rCairoCommon.clipRegion(cr); + + bool bRetval(CairoCommon::drawPolyLine(cr, &aExtents, m_rCairoCommon.m_aLineColor, + getAntiAlias(), rObjectToDevice, rPolyLine, + fTransparency, fLineWidth, pStroke, eLineJoin, eLineCap, + fMiterMinimumAngle, bPixelSnapHairline)); + + m_rCairoCommon.releaseCairoContext(cr, false, aExtents); + + return bRetval; } bool SvpGraphicsBackend::drawPolyLineBezier(sal_uInt32, const Point*, const PolyFlags*) diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index c4f0810c8b83..ce9f7928a1bb 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -852,26 +852,6 @@ void SvpSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) rDPIX = rDPIY = 96; } -void SvpSalGraphics::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); - - drawPolyLine( - basegfx::B2DHomMatrix(), - aPoly, - 0.0, - 1.0, - nullptr, // MM01 - basegfx::B2DLineJoin::Miter, - css::drawing::LineCap_BUTT, - basegfx::deg2rad(15.0) /*default*/, - false); -} - void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry) { basegfx::B2DPolygon aPoly; @@ -885,323 +865,6 @@ void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry) 0.0); } -bool SvpSalGraphics::drawPolyLine( - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolygon& rPolyLine, - 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 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0) - { - return true; - } - - // Wrap call to static version of ::drawPolyLine by - // preparing/getting some local data and parameters - // due to usage in vcl/unx/generic/gdi/salgdi.cxx. - // This is mainly about extended handling of extents - // and the way destruction of CairoContext is handled - // due to current XOR stuff - cairo_t* cr = m_aCairoCommon.getCairoContext(false, getAntiAlias()); - basegfx::B2DRange aExtents; - clipRegion(cr); - - bool bRetval( - drawPolyLine( - cr, - &aExtents, - m_aCairoCommon.m_aLineColor, - getAntiAlias(), - rObjectToDevice, - rPolyLine, - fTransparency, - fLineWidth, - pStroke, // MM01 - eLineJoin, - eLineCap, - fMiterMinimumAngle, - bPixelSnapHairline)); - - m_aCairoCommon.releaseCairoContext(cr, false, aExtents); - - return bRetval; -} - -bool SvpSalGraphics::drawPolyLine( - cairo_t* cr, - basegfx::B2DRange* pExtents, - const Color& rLineColor, - bool bAntiAlias, - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolygon& rPolyLine, - 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 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0) - { - return true; - } - - // need to check/handle LineWidth when ObjectToDevice transformation is used - const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity()); - - // tdf#124848 calculate-back logical LineWidth for a hairline - // since this implementation hands over the transformation to - // the graphic sub-system - if(fLineWidth == 0) - { - fLineWidth = 1.0; - - if(!bObjectToDeviceIsIdentity) - { - basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice); - aObjectToDeviceInv.invert(); - fLineWidth = (aObjectToDeviceInv * basegfx::B2DVector(fLineWidth, 0)).getLength(); - } - } - - // PixelOffset used: Need to reflect in linear transformation - cairo_matrix_t aMatrix; - basegfx::B2DHomMatrix aDamageMatrix(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5)); - - if (bObjectToDeviceIsIdentity) - { - // Set PixelOffset as requested - cairo_matrix_init_translate(&aMatrix, 0.5, 0.5); - } - else - { - // Prepare ObjectToDevice transformation. Take PixelOffset for Lines into - // account: Multiply from left to act in DeviceCoordinates - aDamageMatrix = aDamageMatrix * rObjectToDevice; - cairo_matrix_init( - &aMatrix, - aDamageMatrix.get( 0, 0 ), - aDamageMatrix.get( 1, 0 ), - aDamageMatrix.get( 0, 1 ), - aDamageMatrix.get( 1, 1 ), - aDamageMatrix.get( 0, 2 ), - aDamageMatrix.get( 1, 2 )); - } - - // set linear transformation - cairo_set_matrix(cr, &aMatrix); - - // setup line attributes - cairo_line_join_t eCairoLineJoin = CAIRO_LINE_JOIN_MITER; - switch (eLineJoin) - { - case basegfx::B2DLineJoin::Bevel: - eCairoLineJoin = CAIRO_LINE_JOIN_BEVEL; - break; - case basegfx::B2DLineJoin::Round: - eCairoLineJoin = CAIRO_LINE_JOIN_ROUND; - break; - case basegfx::B2DLineJoin::NONE: - case basegfx::B2DLineJoin::Miter: - eCairoLineJoin = CAIRO_LINE_JOIN_MITER; - break; - } - - // convert miter minimum angle to miter limit - double fMiterLimit = 1.0 / sin( fMiterMinimumAngle / 2.0); - - // setup cap attribute - cairo_line_cap_t eCairoLineCap(CAIRO_LINE_CAP_BUTT); - - switch (eLineCap) - { - default: // css::drawing::LineCap_BUTT: - { - eCairoLineCap = CAIRO_LINE_CAP_BUTT; - break; - } - case css::drawing::LineCap_ROUND: - { - eCairoLineCap = CAIRO_LINE_CAP_ROUND; - break; - } - case css::drawing::LineCap_SQUARE: - { - eCairoLineCap = CAIRO_LINE_CAP_SQUARE; - break; - } - } - - cairo_set_source_rgba( - cr, - rLineColor.GetRed()/255.0, - rLineColor.GetGreen()/255.0, - rLineColor.GetBlue()/255.0, - 1.0-fTransparency); - - cairo_set_line_join(cr, eCairoLineJoin); - cairo_set_line_cap(cr, eCairoLineCap); - cairo_set_line_width(cr, fLineWidth); - cairo_set_miter_limit(cr, fMiterLimit); - - // try to access buffered data - std::shared_ptr<SystemDependentData_CairoPath> pSystemDependentData_CairoPath( - rPolyLine.getSystemDependentData<SystemDependentData_CairoPath>()); - - // 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)); - - // MM01 decide if to stroke directly - static const bool bDoDirectCairoStroke(true); - - // MM01 activate to stroke directly - if(bDoDirectCairoStroke && bStrokeUsed) - { - cairo_set_dash(cr, pStroke->data(), pStroke->size(), 0.0); - } - - if(!bDoDirectCairoStroke && pSystemDependentData_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(bStrokeWasUsed != bStrokeUsed - || (bStrokeUsed && *pStroke != pSystemDependentData_CairoPath->getStroke())) - { - // data invalid, forget - pSystemDependentData_CairoPath.reset(); - } - } - - // check for basegfx::B2DLineJoin::NONE to react accordingly - const bool bNoJoin((basegfx::B2DLineJoin::NONE == eLineJoin - && basegfx::fTools::more(fLineWidth, 0.0))); - - if(pSystemDependentData_CairoPath) - { - // check data validity - if(nullptr == pSystemDependentData_CairoPath->getCairoPath() - || pSystemDependentData_CairoPath->getNoJoin() != bNoJoin - || pSystemDependentData_CairoPath->getAntiAlias() != bAntiAlias - || bPixelSnapHairline /*tdf#124700*/ ) - { - // data invalid, forget - pSystemDependentData_CairoPath.reset(); - } - } - - if(pSystemDependentData_CairoPath) - { - // re-use data - cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath()); - } - else - { - // create data - size_t nSizeMeasure(0); - - // MM01 need to do line dashing as fallback stuff here now - basegfx::B2DPolyPolygon aPolyPolygonLine; - - if(!bDoDirectCairoStroke && bStrokeUsed) - { - // apply LineStyle - basegfx::utils::applyLineDashing( - rPolyLine, // source - *pStroke, // pattern - &aPolyPolygonLine, // target for lines - nullptr, // target for gaps - fDotDashLength); // full length if available - } - else - { - // no line dashing or direct stroke, just copy - aPolyPolygonLine.append(rPolyLine); - } - - // MM01 checked/verified for Cairo - for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) - { - const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); - - if (!bNoJoin) - { - // PixelOffset now reflected in linear transformation used - nSizeMeasure += AddPolygonToPath( - cr, - aPolyLine, - rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset - !bAntiAlias, - 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)); - - 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 - nSizeMeasure += AddPolygonToPath( - cr, - aEdge, - rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset - !bAntiAlias, - bPixelSnapHairline); - - // prepare next step - aEdge.setB2DPoint(0, aEdge.getB2DPoint(1)); - } - } - } - - // copy and add to buffering mechanism - if (!bPixelSnapHairline /*tdf#124700*/) - { - pSystemDependentData_CairoPath = rPolyLine.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>( - ImplGetSystemDependentDataManager(), - nSizeMeasure, - cr, - bNoJoin, - bAntiAlias, - pStroke); - } - } - - // extract extents - if (pExtents) - { - *pExtents = getClippedStrokeDamage(cr); - // transform also extents (ranges) of damage so they can be correctly redrawn - pExtents->transform(aDamageMatrix); - } - - // draw and consume - cairo_stroke(cr); - - return true; -} - bool SvpSalGraphics::drawGradient(const tools::PolyPolygon& rPolyPolygon, const Gradient& rGradient) { if (rGradient.GetStyle() != GradientStyle::Linear diff --git a/vcl/inc/headless/CairoCommon.hxx b/vcl/inc/headless/CairoCommon.hxx index 2f3cc16badfa..038bd3a42c35 100644 --- a/vcl/inc/headless/CairoCommon.hxx +++ b/vcl/inc/headless/CairoCommon.hxx @@ -28,11 +28,14 @@ #include <vcl/region.hxx> #include <vcl/salgtype.hxx> -#include <basegfx/utils/systemdependentdata.hxx> +#include <com/sun/star/drawing/LineCap.hpp> +#include <basegfx/utils/systemdependentdata.hxx> #include <basegfx/range/b2drange.hxx> #include <basegfx/range/b2irange.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> //Using formats that match cairo's formats. For android we patch cairo, //which is internal in that case, to swap the rgb components so that @@ -162,6 +165,16 @@ struct VCL_DLLPUBLIC CairoCommon void applyColor(cairo_t* cr, Color rColor, double fTransparency = 0.0); void clipRegion(cairo_t* cr); static void clipRegion(cairo_t* cr, const vcl::Region& rClipRegion); + + // 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 bool drawPolyLine(cairo_t* cr, basegfx::B2DRange* pExtents, const Color& rLineColor, + bool bAntiAlias, const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, double fTransparency, + double fLineWidth, const std::vector<double>* pStroke, + basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, bool bPixelSnapHairline); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index b9ece62a2267..e38aa3be55a4 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -54,24 +54,6 @@ public: return CairoCommon::getDamageKey(); } - // 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 bool drawPolyLine( - cairo_t* cr, - basegfx::B2DRange* pExtents, - const Color& rLineColor, - bool bAntiAlias, - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolygon& rPolyLine, - double fTransparency, - double fLineWidth, - const std::vector< double >* pStroke, // MM01 - basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap, - double fMiterMinimumAngle, - bool bPixelSnapHairline); - void copySource(const SalTwoRect& rTR, cairo_surface_t* source); void copyWithOperator(const SalTwoRect& rTR, cairo_surface_t* source, cairo_operator_t eOp = CAIRO_OPERATOR_SOURCE); @@ -137,17 +119,6 @@ public: virtual void DrawTextLayout( const GenericSalLayout& ) override; virtual bool supportsOperation( OutDevSupportType ) const 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 void drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry ) override; virtual void drawPolygon( sal_uInt32 nPoints, const Point* pPtAry ) override; virtual bool drawGradient(tools::PolyPolygon const & rPolyPolygon, Gradient const & rGradient) override; diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index 3b2946e2f18c..b5e1432764e6 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -733,7 +733,7 @@ bool X11SalGraphics::drawPolyLine( // Use the now available static drawPolyLine from the Cairo-Headless-Fallback // that will take care of all needed stuff const bool bRetval( - SvpSalGraphics::drawPolyLine( + CairoCommon::drawPolyLine( cr, nullptr, mnPenColor,