diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2021-11-27 21:29:15 +0100 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2022-01-01 03:50:45 +0100 |
commit | a2da849163cbbba5ab4272999b9fb081240f1786 (patch) | |
tree | 9417ad343bca96706f77902fd67a9004f2f7c3e4 /vcl | |
parent | cf6f1aae98e23227e4a9a17d72801abf38c6259f (diff) |
vcl: move drawRect and drawPolyPolygon to SvpGraphicsBackend
Also move add_polygon_path and SystemDependentData_CairoPath class
to CairoCommon.
SystemDependentData_CairoPath is temporary made public until other
dependencies are moved too.
Change-Id: I381407fc7c168c8982fcfd8c886cf622f95591fd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127711
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/headless/CairoCommon.cxx | 83 | ||||
-rw-r--r-- | vcl/headless/SvpGraphicsBackend.cxx | 104 | ||||
-rw-r--r-- | vcl/headless/svpgdi.cxx | 247 | ||||
-rw-r--r-- | vcl/inc/headless/CairoCommon.hxx | 32 | ||||
-rw-r--r-- | vcl/inc/headless/svpgdi.hxx | 7 |
5 files changed, 214 insertions, 259 deletions
diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx index e79a6b2d6a9b..40115a90db1f 100644 --- a/vcl/headless/CairoCommon.cxx +++ b/vcl/headless/CairoCommon.cxx @@ -20,8 +20,8 @@ #include <headless/CairoCommon.hxx> #include <dlfcn.h> #include <vcl/BitmapTools.hxx> +#include <svdata.hxx> #include <basegfx/utils/canvastools.hxx> - void dl_cairo_surface_set_device_scale(cairo_surface_t* surface, double x_scale, double y_scale) { #ifdef ANDROID @@ -298,6 +298,87 @@ basegfx::B2DPoint impPixelSnap(const basegfx::B2DPolygon& rPolygon, return rPolygon.getB2DPoint(nIndex); } +SystemDependentData_CairoPath::SystemDependentData_CairoPath( + basegfx::SystemDependentDataManager& rSystemDependentDataManager, size_t nSizeMeasure, + cairo_t* cr, bool bNoJoin, bool bAntiAlias, const std::vector<double>* pStroke) + : basegfx::SystemDependentData(rSystemDependentDataManager) + , mpCairoPath(nullptr) + , mbNoJoin(bNoJoin) + , mbAntiAlias(bAntiAlias) +{ + // tdf#129845 only create a copy of the path when nSizeMeasure is + // bigger than some decent threshold + if (nSizeMeasure > 50) + { + mpCairoPath = cairo_copy_path(cr); + + if (nullptr != pStroke) + { + maStroke = *pStroke; + } + } +} + +SystemDependentData_CairoPath::~SystemDependentData_CairoPath() +{ + if (nullptr != mpCairoPath) + { + cairo_path_destroy(mpCairoPath); + mpCairoPath = nullptr; + } +} + +sal_Int64 SystemDependentData_CairoPath::estimateUsageInBytes() const +{ + // tdf#129845 by using the default return value of zero when no path + // was created, SystemDependentData::calculateCombinedHoldCyclesInSeconds + // will do the right thing and not buffer this entry at all + sal_Int64 nRetval(0); + + if (nullptr != mpCairoPath) + { + // per node + // - num_data incarnations of + // - sizeof(cairo_path_data_t) which is a union of defines and point data + // thus may 2 x sizeof(double) + nRetval = mpCairoPath->num_data * sizeof(cairo_path_data_t); + } + + return nRetval; +} + +void add_polygon_path(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPolygon, + const basegfx::B2DHomMatrix& rObjectToDevice, bool bPixelSnap) +{ + // try to access buffered data + std::shared_ptr<SystemDependentData_CairoPath> pSystemDependentData_CairoPath( + rPolyPolygon.getSystemDependentData<SystemDependentData_CairoPath>()); + + if (pSystemDependentData_CairoPath) + { + // re-use data + cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath()); + } + else + { + // create data + size_t nSizeMeasure(0); + + for (const auto& rPoly : rPolyPolygon) + { + // PixelOffset used: Was dependent of 'm_aLineColor != SALCOLOR_NONE' + // Adapt setupPolyPolygon-users to set a linear transformation to achieve PixelOffset + nSizeMeasure += AddPolygonToPath(cr, rPoly, rObjectToDevice, bPixelSnap, false); + } + + // copy and add to buffering mechanism + // for decisions how/what to buffer, see Note in WinSalGraphicsImpl::drawPolyPolygon + pSystemDependentData_CairoPath + = rPolyPolygon.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>( + ImplGetSystemDependentDataManager(), nSizeMeasure, cr, false, false, nullptr); + } +} + cairo_user_data_key_t* CairoCommon::getDamageKey() { static cairo_user_data_key_t aDamageKey; diff --git a/vcl/headless/SvpGraphicsBackend.cxx b/vcl/headless/SvpGraphicsBackend.cxx index d3a53fefe3f1..b44ba3dda90f 100644 --- a/vcl/headless/SvpGraphicsBackend.cxx +++ b/vcl/headless/SvpGraphicsBackend.cxx @@ -151,9 +151,40 @@ void SvpGraphicsBackend::drawLine(tools::Long nX1, tools::Long nY1, tools::Long m_rCairoCommon.releaseCairoContext(cr, false, extents); } -void SvpGraphicsBackend::drawRect(tools::Long /*nX*/, tools::Long /*nY*/, tools::Long /*nWidth*/, - tools::Long /*nHeight*/) +void SvpGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) { + // because of the -1 hack we have to do fill and draw separately + Color aOrigFillColor = m_rCairoCommon.m_aFillColor; + Color aOrigLineColor = m_rCairoCommon.m_aLineColor; + m_rCairoCommon.m_aFillColor = SALCOLOR_NONE; + m_rCairoCommon.m_aLineColor = SALCOLOR_NONE; + + if (aOrigFillColor != SALCOLOR_NONE) + { + basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect( + basegfx::B2DRectangle(nX, nY, nX + nWidth, nY + nHeight)); + m_rCairoCommon.m_aFillColor = aOrigFillColor; + + drawPolyPolygon(basegfx::B2DHomMatrix(), basegfx::B2DPolyPolygon(aRect), 0.0); + + m_rCairoCommon.m_aFillColor = SALCOLOR_NONE; + } + + if (aOrigLineColor != SALCOLOR_NONE) + { + // need same -1 hack as X11SalGraphicsImpl::drawRect + basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect( + basegfx::B2DRectangle(nX, nY, nX + nWidth - 1, nY + nHeight - 1)); + m_rCairoCommon.m_aLineColor = aOrigLineColor; + + drawPolyPolygon(basegfx::B2DHomMatrix(), basegfx::B2DPolyPolygon(aRect), 0.0); + + m_rCairoCommon.m_aLineColor = SALCOLOR_NONE; + } + + m_rCairoCommon.m_aFillColor = aOrigFillColor; + m_rCairoCommon.m_aLineColor = aOrigLineColor; } void SvpGraphicsBackend::drawPolyLine(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/) {} @@ -165,11 +196,72 @@ void SvpGraphicsBackend::drawPolyPolygon(sal_uInt32 /*nPoly*/, const sal_uInt32* { } -bool SvpGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& /*rObjectToDevice*/, - const basegfx::B2DPolyPolygon& /*rPolyPolygon*/, - double /*fTransparency*/) +bool SvpGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) { - return false; + const bool bHasFill(m_rCairoCommon.m_aFillColor != SALCOLOR_NONE); + const bool bHasLine(m_rCairoCommon.m_aLineColor != SALCOLOR_NONE); + + if (0 == rPolyPolygon.count() || !(bHasFill || bHasLine) || fTransparency < 0.0 + || fTransparency >= 1.0) + { + return true; + } + + cairo_t* cr = m_rCairoCommon.getCairoContext(true, getAntiAlias()); + m_rCairoCommon.clipRegion(cr); + + // Set full (Object-to-Device) transformation - if used + if (!rObjectToDevice.isIdentity()) + { + cairo_matrix_t aMatrix; + + cairo_matrix_init(&aMatrix, rObjectToDevice.get(0, 0), rObjectToDevice.get(1, 0), + rObjectToDevice.get(0, 1), rObjectToDevice.get(1, 1), + rObjectToDevice.get(0, 2), rObjectToDevice.get(1, 2)); + cairo_set_matrix(cr, &aMatrix); + } + + // To make releaseCairoContext work, use empty extents + basegfx::B2DRange extents; + + if (bHasFill) + { + add_polygon_path(cr, rPolyPolygon, rObjectToDevice, !getAntiAlias()); + + m_rCairoCommon.applyColor(cr, m_rCairoCommon.m_aFillColor, fTransparency); + // Get FillDamage (will be extended for LineDamage below) + extents = getClippedFillDamage(cr); + + cairo_fill(cr); + } + + if (bHasLine) + { + // PixelOffset used: Set PixelOffset as linear transformation + cairo_matrix_t aMatrix; + cairo_matrix_init_translate(&aMatrix, 0.5, 0.5); + cairo_set_matrix(cr, &aMatrix); + + add_polygon_path(cr, rPolyPolygon, rObjectToDevice, !getAntiAlias()); + + m_rCairoCommon.applyColor(cr, m_rCairoCommon.m_aLineColor, fTransparency); + + // expand with possible StrokeDamage + basegfx::B2DRange stroke_extents = getClippedStrokeDamage(cr); + stroke_extents.transform(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5)); + extents.expand(stroke_extents); + + cairo_stroke(cr); + } + + // if transformation has been applied, transform also extents (ranges) + // of damage so they can be correctly redrawn + extents.transform(rObjectToDevice); + m_rCairoCommon.releaseCairoContext(cr, true, extents); + + return true; } bool SvpGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& /*rObjectToDevice*/, diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index 9e50652928d9..65f9e13aafd5 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -852,45 +852,6 @@ void SvpSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) rDPIX = rDPIY = 96; } -void SvpSalGraphics::drawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) -{ - // because of the -1 hack we have to do fill and draw separately - Color aOrigFillColor = m_aCairoCommon.m_aFillColor; - Color aOrigLineColor = m_aCairoCommon.m_aLineColor; - m_aCairoCommon.m_aFillColor = SALCOLOR_NONE; - m_aCairoCommon.m_aLineColor = SALCOLOR_NONE; - - if (aOrigFillColor != SALCOLOR_NONE) - { - basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(nX, nY, nX+nWidth, nY+nHeight)); - m_aCairoCommon.m_aFillColor = aOrigFillColor; - - drawPolyPolygon( - basegfx::B2DHomMatrix(), - basegfx::B2DPolyPolygon(aRect), - 0.0); - - m_aCairoCommon.m_aFillColor = SALCOLOR_NONE; - } - - if (aOrigLineColor != SALCOLOR_NONE) - { - // need same -1 hack as X11SalGraphicsImpl::drawRect - basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle( nX, nY, nX+nWidth-1, nY+nHeight-1)); - m_aCairoCommon.m_aLineColor = aOrigLineColor; - - drawPolyPolygon( - basegfx::B2DHomMatrix(), - basegfx::B2DPolyPolygon(aRect), - 0.0); - - m_aCairoCommon.m_aLineColor = SALCOLOR_NONE; - } - - m_aCairoCommon.m_aFillColor = aOrigFillColor; - m_aCairoCommon.m_aLineColor = aOrigLineColor; -} - void SvpSalGraphics::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry) { basegfx::B2DPolygon aPoly; @@ -918,7 +879,7 @@ void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry) for (sal_uInt32 i = 1; i < nPoints; ++i) aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].getX(), pPtAry[i].getY())); - drawPolyPolygon( + GetImpl()->drawPolyPolygon( basegfx::B2DHomMatrix(), basegfx::B2DPolyPolygon(aPoly), 0.0); @@ -944,100 +905,12 @@ void SvpSalGraphics::drawPolyPolygon(sal_uInt32 nPoly, } } - drawPolyPolygon( + GetImpl()->drawPolyPolygon( basegfx::B2DHomMatrix(), aPolyPoly, 0.0); } -namespace { - -class SystemDependentData_CairoPath : public basegfx::SystemDependentData -{ -private: - // the path data itself - cairo_path_t* mpCairoPath; - - // all other values the path data is based on and - // need to be compared with to check for data validity - bool mbNoJoin; - bool mbAntiAlias; - std::vector< double > maStroke; - -public: - SystemDependentData_CairoPath( - basegfx::SystemDependentDataManager& rSystemDependentDataManager, - size_t nSizeMeasure, - cairo_t* cr, - bool bNoJoin, - bool bAntiAlias, - const std::vector< double >* pStroke); // MM01 - virtual ~SystemDependentData_CairoPath() override; - - // read access - cairo_path_t* getCairoPath() { return mpCairoPath; } - bool getNoJoin() const { return mbNoJoin; } - bool getAntiAlias() const { return mbAntiAlias; } - const std::vector< double >& getStroke() const { return maStroke; } - - virtual sal_Int64 estimateUsageInBytes() const override; -}; - -} - -SystemDependentData_CairoPath::SystemDependentData_CairoPath( - basegfx::SystemDependentDataManager& rSystemDependentDataManager, - size_t nSizeMeasure, - cairo_t* cr, - bool bNoJoin, - bool bAntiAlias, - const std::vector< double >* pStroke) -: basegfx::SystemDependentData(rSystemDependentDataManager), - mpCairoPath(nullptr), - mbNoJoin(bNoJoin), - mbAntiAlias(bAntiAlias) -{ - // tdf#129845 only create a copy of the path when nSizeMeasure is - // bigger than some decent threshold - if(nSizeMeasure > 50) - { - mpCairoPath = cairo_copy_path(cr); - - if(nullptr != pStroke) - { - maStroke = *pStroke; - } - } -} - -SystemDependentData_CairoPath::~SystemDependentData_CairoPath() -{ - if(nullptr != mpCairoPath) - { - cairo_path_destroy(mpCairoPath); - mpCairoPath = nullptr; - } -} - -sal_Int64 SystemDependentData_CairoPath::estimateUsageInBytes() const -{ - // tdf#129845 by using the default return value of zero when no path - // was created, SystemDependentData::calculateCombinedHoldCyclesInSeconds - // will do the right thing and not buffer this entry at all - sal_Int64 nRetval(0); - - if(nullptr != mpCairoPath) - { - // per node - // - num_data incarnations of - // - sizeof(cairo_path_data_t) which is a union of defines and point data - // thus may 2 x sizeof(double) - nRetval = mpCairoPath->num_data * sizeof(cairo_path_data_t); - } - - return nRetval; -} - bool SvpSalGraphics::drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolyLine, @@ -1380,122 +1253,6 @@ bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32, return false; } -namespace -{ - void add_polygon_path(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DHomMatrix& rObjectToDevice, bool bPixelSnap) - { - // try to access buffered data - std::shared_ptr<SystemDependentData_CairoPath> pSystemDependentData_CairoPath( - rPolyPolygon.getSystemDependentData<SystemDependentData_CairoPath>()); - - if(pSystemDependentData_CairoPath) - { - // re-use data - cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath()); - } - else - { - // create data - size_t nSizeMeasure(0); - - for (const auto & rPoly : rPolyPolygon) - { - // PixelOffset used: Was dependent of 'm_aLineColor != SALCOLOR_NONE' - // Adapt setupPolyPolygon-users to set a linear transformation to achieve PixelOffset - nSizeMeasure += AddPolygonToPath( - cr, - rPoly, - rObjectToDevice, - bPixelSnap, - false); - } - - // copy and add to buffering mechanism - // for decisions how/what to buffer, see Note in WinSalGraphicsImpl::drawPolyPolygon - pSystemDependentData_CairoPath = rPolyPolygon.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>( - ImplGetSystemDependentDataManager(), - nSizeMeasure, - cr, - false, - false, - nullptr); - } - } -} - -bool SvpSalGraphics::drawPolyPolygon( - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolyPolygon& rPolyPolygon, - double fTransparency) -{ - const bool bHasFill(m_aCairoCommon.m_aFillColor != SALCOLOR_NONE); - const bool bHasLine(m_aCairoCommon.m_aLineColor != SALCOLOR_NONE); - - if(0 == rPolyPolygon.count() || !(bHasFill || bHasLine) || fTransparency < 0.0 || fTransparency >= 1.0) - { - return true; - } - - cairo_t* cr = m_aCairoCommon.getCairoContext(true, getAntiAlias()); - clipRegion(cr); - - // Set full (Object-to-Device) transformation - if used - if(!rObjectToDevice.isIdentity()) - { - cairo_matrix_t aMatrix; - - cairo_matrix_init( - &aMatrix, - rObjectToDevice.get( 0, 0 ), - rObjectToDevice.get( 1, 0 ), - rObjectToDevice.get( 0, 1 ), - rObjectToDevice.get( 1, 1 ), - rObjectToDevice.get( 0, 2 ), - rObjectToDevice.get( 1, 2 )); - cairo_set_matrix(cr, &aMatrix); - } - - // To make releaseCairoContext work, use empty extents - basegfx::B2DRange extents; - - if (bHasFill) - { - add_polygon_path(cr, rPolyPolygon, rObjectToDevice, !getAntiAlias()); - - m_aCairoCommon.applyColor(cr, m_aCairoCommon.m_aFillColor, fTransparency); - // Get FillDamage (will be extended for LineDamage below) - extents = getClippedFillDamage(cr); - - cairo_fill(cr); - } - - if (bHasLine) - { - // PixelOffset used: Set PixelOffset as linear transformation - cairo_matrix_t aMatrix; - cairo_matrix_init_translate(&aMatrix, 0.5, 0.5); - cairo_set_matrix(cr, &aMatrix); - - add_polygon_path(cr, rPolyPolygon, rObjectToDevice, !getAntiAlias()); - - m_aCairoCommon.applyColor(cr, m_aCairoCommon.m_aLineColor, fTransparency); - - // expand with possible StrokeDamage - basegfx::B2DRange stroke_extents = getClippedStrokeDamage(cr); - stroke_extents.transform(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5)); - extents.expand(stroke_extents); - - cairo_stroke(cr); - } - - // if transformation has been applied, transform also extents (ranges) - // of damage so they can be correctly redrawn - extents.transform(rObjectToDevice); - m_aCairoCommon.releaseCairoContext(cr, true, extents); - - 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 36acef3c659d..2f3cc16badfa 100644 --- a/vcl/inc/headless/CairoCommon.hxx +++ b/vcl/inc/headless/CairoCommon.hxx @@ -28,6 +28,8 @@ #include <vcl/region.hxx> #include <vcl/salgtype.hxx> +#include <basegfx/utils/systemdependentdata.hxx> + #include <basegfx/range/b2drange.hxx> #include <basegfx/range/b2irange.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> @@ -75,6 +77,33 @@ VCL_DLLPUBLIC basegfx::B2DRange getClippedFillDamage(cairo_t* cr); VCL_DLLPUBLIC basegfx::B2DRange getClippedStrokeDamage(cairo_t* cr); VCL_DLLPUBLIC basegfx::B2DRange getStrokeDamage(cairo_t* cr); +class SystemDependentData_CairoPath : public basegfx::SystemDependentData +{ +private: + // the path data itself + cairo_path_t* mpCairoPath; + + // all other values the path data is based on and + // need to be compared with to check for data validity + bool mbNoJoin; + bool mbAntiAlias; + std::vector<double> maStroke; + +public: + SystemDependentData_CairoPath(basegfx::SystemDependentDataManager& rSystemDependentDataManager, + size_t nSizeMeasure, cairo_t* cr, bool bNoJoin, bool bAntiAlias, + const std::vector<double>* pStroke); // MM01 + virtual ~SystemDependentData_CairoPath() override; + + // read access + cairo_path_t* getCairoPath() { return mpCairoPath; } + bool getNoJoin() const { return mbNoJoin; } + bool getAntiAlias() const { return mbAntiAlias; } + const std::vector<double>& getStroke() const { return maStroke; } + + virtual sal_Int64 estimateUsageInBytes() const override; +}; + VCL_DLLPUBLIC size_t AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rPolygon, const basegfx::B2DHomMatrix& rObjectToDevice, bool bPixelSnap, bool bPixelSnapHairline); @@ -84,6 +113,9 @@ VCL_DLLPUBLIC basegfx::B2DPoint impPixelSnap(const basegfx::B2DPolygon& rPolygon basegfx::B2DHomMatrix& rObjectToDeviceInv, sal_uInt32 nIndex); +VCL_DLLPUBLIC void add_polygon_path(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPolygon, + const basegfx::B2DHomMatrix& rObjectToDevice, bool bPixelSnap); + enum class PaintMode { Over, diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index 5f5be07a43a5..1196b29ca26e 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -137,13 +137,6 @@ public: virtual void DrawTextLayout( const GenericSalLayout& ) override; virtual bool supportsOperation( OutDevSupportType ) const override; - virtual void drawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) override; - - virtual bool drawPolyPolygon( - const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolyPolygon&, - double fTransparency ) override; - virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&, |