diff options
author | Armin Le Grand <Armin.Le.Grand@cib.de> | 2018-09-06 18:15:02 +0200 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@cib.de> | 2018-09-13 08:49:35 +0200 |
commit | 7034311dce663c895577267110baadbec312d491 (patch) | |
tree | 8c1d712cbfb1b15dc492e6e724b6b22892914249 | |
parent | d92b0efe58b77247e1e5292c1a989baa934df797 (diff) |
Support buffering SystemDependent GraphicData (II)
In this step I have changed all calls that use a
B2DPolyPolygon and do filled graphics, added support for
providing needed transformation which will -if supported-
be used. Added buffering of SystemDependentData at
B2DPolyPolygon for that purpose, see comments describing
the current possibilities in the Gdiplus implementation.
Moved lifetime creation/cleanup of SystemDependentDataManager
to ImplSVData due to cleanup problems in the clang build
Tried to use a std::unique_ptr to hold the instance
of a SystemDependentDataBuffer at ImplSVData and cleanup
inside DeInitVCL() right before ::ImplDeInitScheduler. This
works in principle, but scheduler shutdown triggers
ProcessEventsToIdle which leads to repaints and re-creates
the buffer. Will now do exactly as was done with GdiPlusBuffer
before, a simple local static incarnation and a call to
SetStatic() in constructor
Splitted SystemDependentDataBuffer and Timer due to
different LifeTimes. Timer needs to be destructed
earlier than SystemDependentDataBuffer, before
Scheduler::ImplDeInitScheduler() is called from
DeInitVCL()
Change-Id: I2134e4346a183a4cee1be3428c51541cc8867c11
Reviewed-on: https://gerrit.libreoffice.org/60102
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@cib.de>
36 files changed, 733 insertions, 424 deletions
diff --git a/basegfx/source/polygon/b2dpolygon.cxx b/basegfx/source/polygon/b2dpolygon.cxx index c94f262d6600..3638424a52e4 100644 --- a/basegfx/source/polygon/b2dpolygon.cxx +++ b/basegfx/source/polygon/b2dpolygon.cxx @@ -467,7 +467,8 @@ private: public: ImplBufferedData() - : mpDefaultSubdivision(), + : basegfx::SystemDependentDataHolder(), + mpDefaultSubdivision(), mpB2DRange() { } diff --git a/basegfx/source/polygon/b2dpolypolygon.cxx b/basegfx/source/polygon/b2dpolypolygon.cxx index a1ac5301c178..0901eafee63b 100644 --- a/basegfx/source/polygon/b2dpolypolygon.cxx +++ b/basegfx/source/polygon/b2dpolypolygon.cxx @@ -22,22 +22,63 @@ #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> - +#include <basegfx/utils/systemdependentdata.hxx> #include <functional> #include <algorithm> class ImplB2DPolyPolygon { - basegfx::B2DPolygonVector maPolygons; + basegfx::B2DPolygonVector maPolygons; + std::unique_ptr< basegfx::SystemDependentDataHolder > mpSystemDependentDataHolder; public: - ImplB2DPolyPolygon() : maPolygons() + ImplB2DPolyPolygon() + : maPolygons(), + mpSystemDependentDataHolder() + { + } + + explicit ImplB2DPolyPolygon(const ImplB2DPolyPolygon& rSource) + : maPolygons(rSource.maPolygons), + mpSystemDependentDataHolder() + { + } + + explicit ImplB2DPolyPolygon(const basegfx::B2DPolygon& rToBeCopied) + : maPolygons(1,rToBeCopied), + mpSystemDependentDataHolder() + { + } + + ImplB2DPolyPolygon& operator=(const ImplB2DPolyPolygon& rSource) + { + if (this != &rSource) + { + maPolygons = rSource.maPolygons; + mpSystemDependentDataHolder.reset(); + } + + return *this; + } + + void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr& rData) { + if(!mpSystemDependentDataHolder) + { + mpSystemDependentDataHolder.reset(new basegfx::SystemDependentDataHolder()); + } + + mpSystemDependentDataHolder->addOrReplaceSystemDependentData(rData); } - explicit ImplB2DPolyPolygon(const basegfx::B2DPolygon& rToBeCopied) : - maPolygons(1,rToBeCopied) + basegfx::SystemDependentData_SharedPtr getSystemDependentData(size_t hash_code) const { + if(!mpSystemDependentDataHolder) + { + return basegfx::SystemDependentData_SharedPtr(); + } + + return mpSystemDependentDataHolder->getSystemDependentData(hash_code); } bool operator==(const ImplB2DPolyPolygon& rPolygonList) const @@ -385,6 +426,24 @@ namespace basegfx { return mpPolyPolygon->end(); } + + void B2DPolyPolygon::addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const + { + // Need to get ImplB2DPolyPolygon* from cow_wrapper *without* + // calling make_unique() here - we do not want to + // 'modify' the ImplB2DPolyPolygon, but add buffered data that + // is valid for all referencing instances + const B2DPolyPolygon* pMe(this); + const ImplB2DPolyPolygon* pMyImpl(pMe->mpPolyPolygon.get()); + + const_cast<ImplB2DPolyPolygon*>(pMyImpl)->addOrReplaceSystemDependentData(rData); + } + + SystemDependentData_SharedPtr B2DPolyPolygon::getSystemDependantDataInternal(size_t hash_code) const + { + return mpPolyPolygon->getSystemDependentData(hash_code); + } + } // end of namespace basegfx /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 3295a97129f3..002ae53c6560 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -107,9 +107,7 @@ namespace drawinglayer void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency) { - basegfx::B2DPolyPolygon aLocalPolyPolygon(rSource.getB2DPolyPolygon()); - - if(!aLocalPolyPolygon.count()) + if(!rSource.getB2DPolyPolygon().count()) { // no geometry, done return; @@ -119,9 +117,9 @@ namespace drawinglayer mpOutputDevice->SetFillColor(Color(aPolygonColor)); mpOutputDevice->SetLineColor(); - aLocalPolyPolygon.transform(maCurrentTransformation); mpOutputDevice->DrawTransparent( - aLocalPolyPolygon, + maCurrentTransformation, + rSource.getB2DPolyPolygon(), fTransparency); } diff --git a/include/basegfx/polygon/b2dpolypolygon.hxx b/include/basegfx/polygon/b2dpolypolygon.hxx index fff49fb86c45..65e3b97cfc96 100644 --- a/include/basegfx/polygon/b2dpolypolygon.hxx +++ b/include/basegfx/polygon/b2dpolypolygon.hxx @@ -126,6 +126,26 @@ namespace basegfx const B2DPolygon* end() const; B2DPolygon* begin(); B2DPolygon* end(); + + // exclusive management op's for SystemDependentData at B2DPolygon + template<class T> + std::shared_ptr<T> getSystemDependentData() const + { + return std::static_pointer_cast<T>(getSystemDependantDataInternal(typeid(T).hash_code())); + } + + template<class T, class... Args> + std::shared_ptr<T> addOrReplaceSystemDependentData(SystemDependentDataManager& manager, Args&&... args) const + { + std::shared_ptr<T> r = std::make_shared<T>(manager, std::forward<Args>(args)...); + basegfx::SystemDependentData_SharedPtr r2(r); + addOrReplaceSystemDependentDataInternal(r2); + return r; + } + + private: + void addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const; + SystemDependentData_SharedPtr getSystemDependantDataInternal(size_t hash_code) const; }; // typedef for a vector of B2DPolyPolygons diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index f015f52488d8..13ac5a5d05d4 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -1611,7 +1611,12 @@ public: void DrawTransparent( const tools::PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent ); - void DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency); + + void DrawTransparent( + const basegfx::B2DHomMatrix& rObjectTransform, + const basegfx::B2DPolyPolygon& rB2DPolyPoly, + double fTransparency); + void DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos, const Size& rSize, const Gradient& rTransparenceGradient ); diff --git a/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx index 5615003f89ec..af3fa0a2566e 100644 --- a/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx +++ b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx @@ -215,6 +215,7 @@ Point InsertionIndicatorOverlay::PaintRepresentatives ( rContent.SetFillColor(COL_BLACK); rContent.SetLineColor(); rContent.DrawTransparent( + basegfx::B2DHomMatrix(), ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect( ::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right()+1, aBox.Bottom()+1), 0, diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index 5acd288e8787..56bd740dbe40 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -714,7 +714,10 @@ void SvpSalGraphics::drawPixel( long nX, long nY, Color nColor ) m_aLineColor = SALCOLOR_NONE; m_aFillColor = nColor; - drawPolyPolygon(basegfx::B2DPolyPolygon(aRect)); + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aRect), + 0.0); m_aFillColor = aOrigFillColor; m_aLineColor = aOrigLineColor; @@ -732,7 +735,12 @@ void SvpSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) { basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(nX, nY, nX+nWidth, nY+nHeight)); m_aFillColor = aOrigFillColor; - drawPolyPolygon(basegfx::B2DPolyPolygon(aRect)); + + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aRect), + 0.0); + m_aFillColor = SALCOLOR_NONE; } @@ -741,7 +749,12 @@ void SvpSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) // need same -1 hack as X11SalGraphicsImpl::drawRect basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle( nX, nY, nX+nWidth-1, nY+nHeight-1)); m_aLineColor = aOrigLineColor; - drawPolyPolygon(basegfx::B2DPolyPolygon(aRect)); + + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aRect), + 0.0); + m_aLineColor = SALCOLOR_NONE; } @@ -775,7 +788,10 @@ void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) for (sal_uInt32 i = 1; i < nPoints; ++i) aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); - drawPolyPolygon(basegfx::B2DPolyPolygon(aPoly)); + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aPoly), + 0.0); } void SvpSalGraphics::drawPolyPolygon(sal_uInt32 nPoly, @@ -798,7 +814,10 @@ void SvpSalGraphics::drawPolyPolygon(sal_uInt32 nPoly, } } - drawPolyPolygon(aPolyPoly); + drawPolyPolygon( + basegfx::B2DHomMatrix(), + aPolyPoly, + 0.0); } basegfx::B2DPoint impPixelSnap( @@ -1061,7 +1080,7 @@ bool SvpSalGraphics::drawPolyLine( bool bPixelSnapHairline) { // short circuit if there is nothing to do - if(0 == rPolyLine.count()) + if(0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0) { return true; } @@ -1111,7 +1130,7 @@ bool SvpSalGraphics::drawPolyLine( bool bPixelSnapHairline) { // short circuit if there is nothing to do - if(0 == rPolyLine.count()) + if(0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0) { return true; } @@ -1283,7 +1302,7 @@ bool SvpSalGraphics::drawPolyLine( // copy and add to buffering mechanism pSystemDependentData_CairoPath = rPolyLine.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>( - SalGraphics::getSystemDependentDataManager(), + ImplGetSystemDependentDataManager(), cairo_copy_path(cr)); // fill data of buffered data @@ -1337,36 +1356,68 @@ bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32, return false; } -void SvpSalGraphics::setupPolyPolygon(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPoly) -{ - clipRegion(cr); - - for (const auto & rPoly : rPolyPoly) - { - // PixelOffset used: Was dependent of 'm_aLineColor != SALCOLOR_NONE' - // Adapt setupPolyPolygon-users to set a linear transformation to achieve PixelOffset - AddPolygonToPath( - cr, - rPoly, - basegfx::B2DHomMatrix(), - !getAntiAliasB2DDraw(), - false); - } -} - -bool SvpSalGraphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly, double fTransparency) +bool SvpSalGraphics::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) { const bool bHasFill(m_aFillColor != SALCOLOR_NONE); const bool bHasLine(m_aLineColor != SALCOLOR_NONE); - if(0 == rPolyPoly.count() || !(bHasFill || bHasLine)) + if(0 == rPolyPolygon.count() || !(bHasFill || bHasLine) || fTransparency < 0.0 || fTransparency >= 1.0) { return true; } cairo_t* cr = getCairoContext(true); + 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); + } - setupPolyPolygon(cr, rPolyPoly); + // 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 + 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 + AddPolygonToPath( + cr, + rPoly, + rObjectToDevice, + !getAntiAliasB2DDraw(), + 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(), + cairo_copy_path(cr)); + } // To make releaseCairoContext work, use empty extents basegfx::B2DRange extents; @@ -1426,51 +1477,6 @@ void SvpSalGraphics::applyColor(cairo_t *cr, Color aColor) } } -void SvpSalGraphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly) -{ - const bool bHasFill(m_aFillColor != SALCOLOR_NONE); - const bool bHasLine(m_aLineColor != SALCOLOR_NONE); - - if(0 == rPolyPoly.count() || !(bHasFill || bHasLine)) - { - return; - } - - cairo_t* cr = getCairoContext(true); - - setupPolyPolygon(cr, rPolyPoly); - - // To make releaseCairoContext work, use empty extents - basegfx::B2DRange extents; - - if (bHasFill) - { - applyColor(cr, m_aFillColor); - - // Get FillDamage (will be extended for LineDamage below) - extents = getClippedFillDamage(cr); - - cairo_fill_preserve(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); - - applyColor(cr, m_aLineColor); - - // expand with possible StrokeDamage - extents.expand(getClippedStrokeDamage(cr)); - - cairo_stroke_preserve(cr); - } - - releaseCairoContext(cr, true, extents); -} - void SvpSalGraphics::copyArea( long nDestX, long nDestY, long nSrcX, diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index 158c331eded6..9c7ee0391f47 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -122,9 +122,8 @@ private: 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); - void setupPolyPolygon(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPoly); void applyColor(cairo_t *cr, Color rColor); - void drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly); + protected: vcl::Region m_aClipRegion; SvpCairoTextRender m_aTextRenderImpl; @@ -200,7 +199,12 @@ public: virtual void drawPixel( long nX, long nY, Color nColor ) override; virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) override; virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) override; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency ) override; + virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&, diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx index f2fd9b7819dd..bc19dcd338fb 100644 --- a/vcl/inc/openglgdiimpl.hxx +++ b/vcl/inc/openglgdiimpl.hxx @@ -249,7 +249,11 @@ public: virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, diff --git a/vcl/inc/qt5/Qt5Graphics.hxx b/vcl/inc/qt5/Qt5Graphics.hxx index 6bde41ffa27f..76c39146728c 100644 --- a/vcl/inc/qt5/Qt5Graphics.hxx +++ b/vcl/inc/qt5/Qt5Graphics.hxx @@ -108,7 +108,8 @@ public: virtual void drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) override; virtual void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry) override; - virtual bool drawPolyPolygon(const basegfx::B2DPolyPolygon&, double fTransparency) override; + virtual bool drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, double fTransparency) override; virtual bool drawPolyLineBezier(sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry) override; virtual bool drawPolygonBezier(sal_uInt32 nPoints, const SalPoint* pPtAry, diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index b03fa5b6b3b2..24b5268493de 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -224,7 +224,10 @@ public: virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override; + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override; virtual bool drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override; virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const PolyFlags* const* pFlgAry ) override; diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index 31c484885a2b..19fac921d2fb 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -55,7 +55,6 @@ namespace basegfx { class B2DVector; class B2DPolygon; class B2DPolyPolygon; - class SystemDependentDataManager; } typedef sal_Unicode sal_Ucs; // TODO: use sal_UCS4 instead of sal_Unicode @@ -78,10 +77,6 @@ public: virtual SalGraphicsImpl* GetImpl() const = 0; - // access to single global managing instance of a basegfx::SystemDependentDataManager, - // used to handle graphic data in system-dependent form - static basegfx::SystemDependentDataManager& getSystemDependentDataManager(); - /// Check that our mpImpl is OpenGL and return the context, otherwise NULL. rtl::Reference<OpenGLContext> GetOpenGLContext() const; @@ -244,6 +239,7 @@ public: const OutputDevice *pOutDev ); bool DrawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolyPolygon &i_rPolyPolygon, double i_fTransparency, const OutputDevice *i_pOutDev); @@ -464,7 +460,11 @@ protected: virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0; virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) = 0; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) = 0; virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx index 8e545d093d20..d4023bd52947 100644 --- a/vcl/inc/salgdiimpl.hxx +++ b/vcl/inc/salgdiimpl.hxx @@ -100,7 +100,11 @@ public: virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0; virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) = 0; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) = 0; virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx index 679debce188e..6ef279586ea1 100644 --- a/vcl/inc/svdata.hxx +++ b/vcl/inc/svdata.hxx @@ -106,6 +106,11 @@ namespace vcl class Window; } +namespace basegfx +{ + class SystemDependentDataManager; +} + class LocaleConfigurationListener : public utl::ConfigurationListener { public: @@ -372,6 +377,7 @@ struct ImplSVData css::uno::Reference<css::i18n::XCharacterClassification> const& ImplGetCharClass(); void ImplDeInitSVData(); +VCL_PLUGIN_PUBLIC basegfx::SystemDependentDataManager& ImplGetSystemDependentDataManager(); VCL_PLUGIN_PUBLIC vcl::Window* ImplGetDefaultWindow(); VCL_PLUGIN_PUBLIC vcl::Window* ImplGetDefaultContextWindow(); VCL_PLUGIN_PUBLIC const std::locale& ImplGetResLocale(); diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h index 3f6bae6c0744..bddcb888ebc6 100644 --- a/vcl/inc/unx/genpspgraphics.h +++ b/vcl/inc/unx/genpspgraphics.h @@ -126,8 +126,12 @@ public: virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, - double fTransparency ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; + virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&, diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index 8b73c4583243..d6054eae4b4c 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -160,7 +160,10 @@ public: const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override; + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index 9f30f57ecac8..e8fe72cc4ca7 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -221,7 +221,10 @@ protected: virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override; + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&, diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index 4c966bd408ef..082c8d66b7b0 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -1567,7 +1567,10 @@ void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPt for (sal_uInt32 i = 1; i < nPoints; ++i) aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); - drawPolyPolygon(basegfx::B2DPolyPolygon(aPoly), 0.0); + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aPoly), + 0.0); } void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPointCounts, PCONSTSALPOINT* pPtAry ) @@ -1589,13 +1592,30 @@ void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* } } - drawPolyPolygon(aPolyPoly, 0.0); + drawPolyPolygon( + basegfx::B2DHomMatrix(), + aPolyPoly, + 0.0); } -bool OpenGLSalGraphicsImpl::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) +bool OpenGLSalGraphicsImpl::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) { VCL_GL_INFO("::drawPolyPolygon " << rPolyPolygon.getB2DRange()); - mpRenderList->addDrawPolyPolygon(rPolyPolygon, fTransparency, mnLineColor, mnFillColor, mrParent.getAntiAliasB2DDraw()); + + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + + mpRenderList->addDrawPolyPolygon( + aPolyPolygon, + fTransparency, + mnLineColor, + mnFillColor, + mrParent.getAntiAliasB2DDraw()); + PostBatchDraw(); return true; } diff --git a/vcl/qt5/Qt5Graphics_GDI.cxx b/vcl/qt5/Qt5Graphics_GDI.cxx index 3b8d2ee80d3c..f8ab00ea1494 100644 --- a/vcl/qt5/Qt5Graphics_GDI.cxx +++ b/vcl/qt5/Qt5Graphics_GDI.cxx @@ -279,7 +279,8 @@ void Qt5Graphics::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt32* pPoin aPainter.update(aPath.boundingRect()); } -bool Qt5Graphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly, double fTransparency) +bool Qt5Graphics::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) { // ignore invisible polygons if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) @@ -287,9 +288,13 @@ bool Qt5Graphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly, doub if ((fTransparency >= 1.0) || (fTransparency < 0)) return true; + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + QPainterPath aPath; // ignore empty polygons - if (!AddPolyPolygonToPath(aPath, rPolyPoly, !getAntiAliasB2DDraw(), + if (!AddPolyPolygonToPath(aPath, aPolyPolygon, !getAntiAliasB2DDraw(), m_aLineColor != SALCOLOR_NONE)) return true; diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx index 09adf784d2ad..59d836506b52 100644 --- a/vcl/quartz/salgdicommon.cxx +++ b/vcl/quartz/salgdicommon.cxx @@ -1072,13 +1072,15 @@ bool AquaSalGraphics::drawPolyLineBezier( sal_uInt32, const SalPoint*, const Pol return false; } -bool AquaSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, - double fTransparency ) +bool AquaSalGraphics::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) { DBG_DRAW_OPERATION("drawPolyPolygon", true); // short circuit if there is nothing to do - const int nPolyCount = rPolyPoly.count(); + const int nPolyCount = rPolyPolygon.count(); if( nPolyCount <= 0 ) { DBG_DRAW_OPERATION_EXIT_EARLY("drawPolyPolygon"); @@ -1092,12 +1094,16 @@ bool AquaSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, return true; } + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + // setup poly-polygon path CGMutablePathRef xPath = CGPathCreateMutable(); SAL_INFO( "vcl.cg", "CGPathCreateMutable() = " << xPath ); for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) { - const basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx ); + const basegfx::B2DPolygon rPolygon = rPolyPolygon.getB2DPolygon( nPolyIdx ); AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() ); } diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index 93fcfeca7df9..9e5c3bc8db72 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -155,7 +155,7 @@ void Scheduler::ImplDeInitScheduler() || !strcmp( pTask->GetDebugName(), "svtools::GraphicCache maReleaseTimer" ) || !strcmp( pTask->GetDebugName(), "svtools::GraphicObject mpSwapOutTimer" ) || !strcmp( pTask->GetDebugName(), "svx OLEObjCache pTimer UnloadCheck" ) - || !strcmp( pTask->GetDebugName(), "vcl::win GdiPlusBuffer aGdiPlusBuffer" ) + || !strcmp( pTask->GetDebugName(), "vcl SystemDependentDataBuffer aSystemDependentDataBuffer" ) )) { sIgnored = " (ignored)"; diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx index ce3ed1393729..251da9e6b1a5 100644 --- a/vcl/source/app/svdata.cxx +++ b/vcl/source/app/svdata.cxx @@ -60,6 +60,9 @@ #if HAVE_FEATURE_OPENGL #include <vcl/opengl/OpenGLContext.hxx> #endif +#include <basegfx/utils/systemdependentdata.hxx> +#include <cppuhelper/basemutex.hxx> +#include <o3tl/make_unique.hxx> using namespace com::sun::star::uno; using namespace com::sun::star::lang; @@ -97,6 +100,135 @@ void ImplDeInitSVData() pSVData->maPaperNames.clear(); } +namespace +{ + typedef ::std::map< basegfx::SystemDependentData_SharedPtr, sal_uInt32 > EntryMap; + + class SystemDependentDataBuffer : public basegfx::SystemDependentDataManager, protected cppu::BaseMutex + { + private: + std::unique_ptr<Timer> maTimer; + EntryMap maEntries; + + DECL_LINK(implTimeoutHdl, Timer *, void); + + public: + SystemDependentDataBuffer(const sal_Char* pDebugName) + : basegfx::SystemDependentDataManager(), + maTimer(o3tl::make_unique<Timer>(pDebugName)), + maEntries() + { + maTimer->SetTimeout(1000); + maTimer->SetInvokeHandler(LINK(this, SystemDependentDataBuffer, implTimeoutHdl)); + } + + virtual ~SystemDependentDataBuffer() override + { + flushAll(); + } + + void startUsage(basegfx::SystemDependentData_SharedPtr& rData) override + { + ::osl::MutexGuard aGuard(m_aMutex); + EntryMap::iterator aFound(maEntries.find(rData)); + + if(aFound == maEntries.end()) + { + if(maEntries.empty() && maTimer) + { + maTimer->Start(); + } + + maEntries[rData] = rData->getHoldCycles(); + } + } + + void endUsage(basegfx::SystemDependentData_SharedPtr& rData) override + { + ::osl::MutexGuard aGuard(m_aMutex); + EntryMap::iterator aFound(maEntries.find(rData)); + + if(aFound != maEntries.end()) + { + maEntries.erase(aFound); + + if(maEntries.empty() && maTimer) + { + maTimer->Stop(); + } + } + } + + void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) override + { + ::osl::MutexGuard aGuard(m_aMutex); + EntryMap::iterator aFound(maEntries.find(rData)); + + if(aFound != maEntries.end()) + { + aFound->second = rData->getHoldCycles(); + } + } + + void flushAll() override + { + ::osl::MutexGuard aGuard(m_aMutex); + EntryMap::iterator aIter(maEntries.begin()); + + if(maTimer) + { + maTimer->Stop(); + maTimer.reset(); + } + + while(aIter != maEntries.end()) + { + EntryMap::iterator aDelete(aIter); + ++aIter; + maEntries.erase(aDelete); + } + } + }; + + IMPL_LINK_NOARG(SystemDependentDataBuffer, implTimeoutHdl, Timer *, void) + { + ::osl::MutexGuard aGuard(m_aMutex); + EntryMap::iterator aIter(maEntries.begin()); + + while(aIter != maEntries.end()) + { + if(aIter->second) + { + aIter->second--; + ++aIter; + } + else + { + EntryMap::iterator aDelete(aIter); + ++aIter; + maEntries.erase(aDelete); + + if(maEntries.empty() && maTimer) + { + maTimer->Stop(); + } + } + } + + if(!maEntries.empty() && maTimer) + { + maTimer->Start(); + } + } +} + +basegfx::SystemDependentDataManager& ImplGetSystemDependentDataManager() +{ + static SystemDependentDataBuffer aSystemDependentDataBuffer("vcl SystemDependentDataBuffer aSystemDependentDataBuffer"); + + return aSystemDependentDataBuffer; +} + /// Returns either the application window, or the default GL context window vcl::Window* ImplGetDefaultWindow() { diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx index beed24273e0d..b4cfa736792c 100644 --- a/vcl/source/app/svmain.cxx +++ b/vcl/source/app/svmain.cxx @@ -428,9 +428,6 @@ void DeInitVCL() } ImplSVData* pSVData = ImplGetSVData(); - // cleanup SystemDependentData - SalGraphics::getSystemDependentDataManager().flushAll(); - // lp#1560328: clear cache before disposing rest of VCL if(pSVData->mpBlendFrameCache) pSVData->mpBlendFrameCache->m_aLastResult.Clear(); @@ -481,6 +478,9 @@ void DeInitVCL() pSVData->mpSettingsConfigItem.reset(); + // empty and deactivate the SystemDependentDataManager + ImplGetSystemDependentDataManager().flushAll(); + Scheduler::ImplDeInitScheduler(); pSVData->maWinData.maMsgBoxImgList.clear(); diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index d39bd333a9cf..d28c751f42a9 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -31,11 +31,8 @@ #include <salgdi.hxx> #include <salframe.hxx> #include <basegfx/numeric/ftools.hxx> //for F_PI180 -#include <basegfx/utils/systemdependentdata.hxx> -#include <cppuhelper/basemutex.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> -#include <o3tl/make_unique.hxx> // The only common SalFrame method @@ -69,131 +66,6 @@ SalGraphics::~SalGraphics() { } -basegfx::SystemDependentDataManager& SalGraphics::getSystemDependentDataManager() -{ - typedef ::std::map< basegfx::SystemDependentData_SharedPtr, sal_uInt32 > EntryMap; - - class SystemDependentDataBuffer : public basegfx::SystemDependentDataManager, protected cppu::BaseMutex, public Timer - { - private: - EntryMap maEntries; - - public: - SystemDependentDataBuffer( const sal_Char *pDebugName ) - : basegfx::SystemDependentDataManager(), - Timer( pDebugName ), - maEntries() - { - SetTimeout(1000); - SetStatic(); - } - - virtual ~SystemDependentDataBuffer() override - { - Stop(); - } - - void startUsage(basegfx::SystemDependentData_SharedPtr& rData) override - { - ::osl::MutexGuard aGuard(m_aMutex); - EntryMap::iterator aFound(maEntries.find(rData)); - - if(aFound == maEntries.end()) - { - if(maEntries.empty()) - { - Start(); - } - - maEntries[rData] = rData->getHoldCycles(); - } - } - - void endUsage(basegfx::SystemDependentData_SharedPtr& rData) override - { - ::osl::MutexGuard aGuard(m_aMutex); - EntryMap::iterator aFound(maEntries.find(rData)); - - if(aFound != maEntries.end()) - { - maEntries.erase(aFound); - - if(maEntries.empty()) - { - Stop(); - } - } - } - - void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) override - { - ::osl::MutexGuard aGuard(m_aMutex); - EntryMap::iterator aFound(maEntries.find(rData)); - - if(aFound != maEntries.end()) - { - aFound->second = rData->getHoldCycles(); - } - } - - void flushAll() override - { - ::osl::MutexGuard aGuard(m_aMutex); - EntryMap::iterator aIter(maEntries.begin()); - - Stop(); - - while(aIter != maEntries.end()) - { - EntryMap::iterator aDelete(aIter); - ++aIter; - maEntries.erase(aDelete); - } - } - - // from parent Timer - virtual void Invoke() override - { - ::osl::MutexGuard aGuard(m_aMutex); - EntryMap::iterator aIter(maEntries.begin()); - - while(aIter != maEntries.end()) - { - if(aIter->second) - { - aIter->second--; - ++aIter; - } - else - { - EntryMap::iterator aDelete(aIter); - ++aIter; - maEntries.erase(aDelete); - - if(maEntries.empty()) - { - Stop(); - } - } - } - - if(!maEntries.empty()) - { - Start(); - } - } - }; - - static std::unique_ptr<SystemDependentDataBuffer> aSystemDependentDataBuffer; - - if(!aSystemDependentDataBuffer) - { - aSystemDependentDataBuffer = o3tl::make_unique<SystemDependentDataBuffer>(nullptr); - } - - return *aSystemDependentDataBuffer.get(); -} - #if HAVE_FEATURE_OPENGL namespace @@ -589,17 +461,50 @@ void SalGraphics::DrawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, drawPolyPolygon( nPoly, pPoints, pPtAry ); } -bool SalGraphics::DrawPolyPolygon( const basegfx::B2DPolyPolygon& i_rPolyPolygon, double i_fTransparency, const OutputDevice* i_pOutDev ) +bool SalGraphics::DrawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& i_rPolyPolygon, + double i_fTransparency, + const OutputDevice* i_pOutDev) { - bool bRet = false; if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) ) { - basegfx::B2DPolyPolygon aMirror( mirror( i_rPolyPolygon, i_pOutDev ) ); - bRet = drawPolyPolygon( aMirror, i_fTransparency ); + // mirroring set + const basegfx::B2DHomMatrix& rMirror(getMirror(i_pOutDev)); + + if(!rMirror.isIdentity()) + { + if(rObjectToDevice.isIdentity()) + { + // There is no ObjectToDevice transformation set. We can just + // use rMirror, that would be the result of the linear combination + return drawPolyPolygon( + rMirror, + i_rPolyPolygon, + i_fTransparency); + } + else + { + // Create the linear combination + basegfx::B2DHomMatrix aLinearCombination(rObjectToDevice); + basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice); + + aLinearCombination = rMirror * aLinearCombination; + aObjectToDeviceInv.invert(); + aLinearCombination = aObjectToDeviceInv * aLinearCombination; + + return drawPolyPolygon( + aLinearCombination, + i_rPolyPolygon, + i_fTransparency); + } + } } - else - bRet = drawPolyPolygon( i_rPolyPolygon, i_fTransparency ); - return bRet; + + return drawPolyPolygon( + rObjectToDevice, + i_rPolyPolygon, + i_fTransparency); } bool SalGraphics::DrawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry, const OutputDevice* pOutDev ) diff --git a/vcl/source/outdev/line.cxx b/vcl/source/outdev/line.cxx index fe16d676c29f..fecacba8f641 100644 --- a/vcl/source/outdev/line.cxx +++ b/vcl/source/outdev/line.cxx @@ -133,10 +133,6 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt ) aB2DPolyLine.transform( aTransform ); const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline); - // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline) - // { - // aB2DPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine); - // } if( mpGraphics->DrawPolyLine( basegfx::B2DHomMatrix(), @@ -287,7 +283,11 @@ void OutputDevice::drawLine( basegfx::B2DPolyPolygon aLinePolyPolygon, const Lin if(bTryAA) { - bDone = mpGraphics->DrawPolyPolygon(aFillPolyPolygon, 0.0, this); + bDone = mpGraphics->DrawPolyPolygon( + basegfx::B2DHomMatrix(), + aFillPolyPolygon, + 0.0, + this); } if(!bDone) diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx index 94ad52a79dbd..1496b1a1daf8 100644 --- a/vcl/source/outdev/polygon.cxx +++ b/vcl/source/outdev/polygon.cxx @@ -70,17 +70,23 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly ) RasterOp::OverPaint == GetRasterOp() && (IsLineColor() || IsFillColor())) { - const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); + const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation()); basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon()); bool bSuccess(true); - // transform the polygon and ensure closed - aB2DPolyPolygon.transform(aTransform); - aB2DPolyPolygon.setClosed(true); + // ensure closed - may be asserted, will prevent buffering + if(!aB2DPolyPolygon.isClosed()) + { + aB2DPolyPolygon.setClosed(true); + } if(IsFillColor()) { - bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this); + bSuccess = mpGraphics->DrawPolyPolygon( + aTransform, + aB2DPolyPolygon, + 0.0, + this); } if(bSuccess && IsLineColor()) @@ -88,15 +94,10 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly ) const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline); - // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline) - // { - // aB2DPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon); - // } - for(sal_uInt32 a(0); bSuccess && a < aB2DPolyPolygon.count(); a++) { bSuccess = mpGraphics->DrawPolyLine( - basegfx::B2DHomMatrix(), + aTransform, aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, @@ -187,17 +188,23 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly ) RasterOp::OverPaint == GetRasterOp() && (IsLineColor() || IsFillColor())) { - const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); + const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation()); basegfx::B2DPolygon aB2DPolygon(rPoly.getB2DPolygon()); bool bSuccess(true); - // transform the polygon and ensure closed - aB2DPolygon.transform(aTransform); - aB2DPolygon.setClosed(true); + // ensure closed - maybe assert, hinders bufering + if(!aB2DPolygon.isClosed()) + { + aB2DPolygon.setClosed(true); + } if(IsFillColor()) { - bSuccess = mpGraphics->DrawPolyPolygon(basegfx::B2DPolyPolygon(aB2DPolygon), 0.0, this); + bSuccess = mpGraphics->DrawPolyPolygon( + aTransform, + basegfx::B2DPolyPolygon(aB2DPolygon), + 0.0, + this); } if(bSuccess && IsLineColor()) @@ -205,13 +212,8 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly ) const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline); - // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline) - // { - // aB2DPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon); - // } - bSuccess = mpGraphics->DrawPolyLine( - basegfx::B2DHomMatrix(), + aTransform, aB2DPolygon, 0.0, aB2DLineWidth, @@ -298,13 +300,19 @@ void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly); bool bSuccess(true); - // transform the polygon and ensure closed - aB2DPolyPolygon.transform(aTransform); - aB2DPolyPolygon.setClosed(true); + // ensure closed - maybe assert, hinders buffering + if(!aB2DPolyPolygon.isClosed()) + { + aB2DPolyPolygon.setClosed(true); + } if(IsFillColor()) { - bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this); + bSuccess = mpGraphics->DrawPolyPolygon( + aTransform, + aB2DPolyPolygon, + 0.0, + this); } if(bSuccess && IsLineColor()) @@ -312,15 +320,10 @@ void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline); - // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline) - // { - // aB2DPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon); - // } - for(sal_uInt32 a(0);bSuccess && a < aB2DPolyPolygon.count(); a++) { bSuccess = mpGraphics->DrawPolyLine( - basegfx::B2DHomMatrix(), + aTransform, aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, diff --git a/vcl/source/outdev/polyline.cxx b/vcl/source/outdev/polyline.cxx index b5c06b9aa411..da8be42cd304 100644 --- a/vcl/source/outdev/polyline.cxx +++ b/vcl/source/outdev/polyline.cxx @@ -71,14 +71,6 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly ) const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 ); const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline); - // transform the polygon - do not (!) - // aB2DPolyLine.transform( aTransform ); - - // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline) - // { - // aB2DPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine); - // } - if(mpGraphics->DrawPolyLine( aTransform, aB2DPolyLine, @@ -350,27 +342,7 @@ bool OutputDevice::DrawPolyLineDirect( const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation() * rObjectTransform); const bool bLineWidthZero(basegfx::fTools::equalZero(fLineWidth)); const basegfx::B2DVector aB2DLineWidth(bLineWidthZero ? 1.0 : fLineWidth, bLineWidthZero ? 1.0 : fLineWidth); - - // transform the line width if used - // if( fLineWidth != 0.0 ) - // { - // aB2DLineWidth = aTransform * basegfx::B2DVector( fLineWidth, fLineWidth ); - // } - - // transform the polygon - no! - // basegfx::B2DPolygon aB2DPolygon(rB2DPolygon); - // aB2DPolygon.transform(aTransform); - const bool bPixelSnapHairline((mnAntialiasing & AntialiasingFlags::PixelSnapHairline) && rB2DPolygon.count() < 1000); - // if((mnAntialiasing & AntialiasingFlags::PixelSnapHairline) && - // aB2DPolygon.count() < 1000) - // { - // // #i98289#, #i101491# - // // better to remove doubles on device coordinates. Also assume from a given amount - // // of points that the single edges are not long enough to smooth - // aB2DPolygon.removeDoublePoints(); - // aB2DPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon); - // } // draw the polyline bool bDrawSuccess = mpGraphics->DrawPolyLine( diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx index ecd63b642b47..5a9bd599a6ff 100644 --- a/vcl/source/outdev/transparent.cxx +++ b/vcl/source/outdev/transparent.cxx @@ -212,7 +212,10 @@ void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask // void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly ) // so when changes are made here do not forget to make changes there, too -void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency) +void OutputDevice::DrawTransparent( + const basegfx::B2DHomMatrix& rObjectTransform, + const basegfx::B2DPolyPolygon& rB2DPolyPoly, + double fTransparency) { assert(!is_double_buffered_window()); @@ -241,16 +244,27 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, (RasterOp::OverPaint == GetRasterOp()) ) { // b2dpolygon support not implemented yet on non-UNX platforms - const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly); - // transform the polygon into device space and ensure it is closed - aB2DPolyPolygon.transform( aTransform ); - aB2DPolyPolygon.setClosed( true ); + // ensure it is closed + if(!aB2DPolyPolygon.isClosed()) + { + // maybe assert, prevents buffering due to making a copy + aB2DPolyPolygon.setClosed( true ); + } + + // create ObjectToDevice transformation + const basegfx::B2DHomMatrix aFullTransform(ImplGetDeviceTransformation() * rObjectTransform); + bool bDrawnOk(true); - bool bDrawnOk = true; if( IsFillColor() ) - bDrawnOk = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this ); + { + bDrawnOk = mpGraphics->DrawPolyPolygon( + aFullTransform, + aB2DPolyPolygon, + fTransparency, + this); + } if( bDrawnOk && IsLineColor() ) { @@ -263,7 +277,7 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, const basegfx::B2DPolygon aOnePoly(aB2DPolyPolygon.getB2DPolygon(nPolyIdx)); mpGraphics->DrawPolyLine( - basegfx::B2DHomMatrix(), + aFullTransform, aOnePoly, fTransparency, aHairlineWidth, @@ -338,9 +352,8 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly InitFillColor(); // get the polygon in device coordinates - basegfx::B2DPolyPolygon aB2DPolyPolygon( rPolyPoly.getB2DPolyPolygon() ); - const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); - aB2DPolyPolygon.transform( aTransform ); + basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon()); + const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation()); const double fTransparency = 0.01 * nTransparencePercent; if( mbFillColor ) @@ -354,13 +367,18 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly // functionality and we use the fallback some lines below (which is not very good, // though. For now, WinSalGraphics::drawPolyPolygon will detect printer usage and // correct the wrong mapping (see there for details) - bDrawn = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this ); + bDrawn = mpGraphics->DrawPolyPolygon( + aTransform, + aB2DPolyPolygon, + fTransparency, + this); } if( mbLineColor ) { // disable the fill color for now mpGraphics->SetFillColor(); + // draw the border line const basegfx::B2DVector aLineWidths( 1, 1 ); const sal_uInt32 nPolyCount(aB2DPolyPolygon.count()); @@ -371,7 +389,7 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly const basegfx::B2DPolygon aPolygon(aB2DPolyPolygon.getB2DPolygon(nPolyIdx)); bDrawn = mpGraphics->DrawPolyLine( - basegfx::B2DHomMatrix(), + aTransform, aPolygon, fTransparency, aLineWidths, @@ -381,6 +399,7 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly bPixelSnapHairline, this ); } + // prepare to restore the fill color mbInitFillColor = mbFillColor; } diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx index c650f9dd4dad..a5fcf86cd3a7 100644 --- a/vcl/unx/generic/gdi/gdiimpl.cxx +++ b/vcl/unx/generic/gdi/gdiimpl.cxx @@ -1442,10 +1442,13 @@ bool X11SalGraphicsImpl::drawEPS( long,long,long,long,void*,sal_uLong ) } // draw a poly-polygon -bool X11SalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency ) +bool X11SalGraphicsImpl::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) { // nothing to do for empty polypolygons - const int nOrigPolyCount = rOrigPolyPoly.count(); + const int nOrigPolyCount = rPolyPolygon.count(); if( nOrigPolyCount <= 0 ) return true; @@ -1464,21 +1467,24 @@ bool X11SalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPo if( pRenderEnv ) return false; + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + // snap to raster if requested - basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly; const bool bSnapToRaster = !mrParent.getAntiAliasB2DDraw(); if( bSnapToRaster ) - aPolyPoly = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly ); + aPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges( aPolyPolygon ); // don't bother with polygons outside of visible area const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() ); - aPolyPoly = basegfx::utils::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false ); - if( !aPolyPoly.count() ) + aPolyPolygon = basegfx::utils::clipPolyPolygonOnRange( aPolyPolygon, aViewRange, true, false ); + if( !aPolyPolygon.count() ) return true; // tessellate the polypolygon into trapezoids basegfx::B2DTrapezoidVector aB2DTrapVector; - basegfx::utils::trapezoidSubdivide( aB2DTrapVector, aPolyPoly ); + basegfx::utils::trapezoidSubdivide( aB2DTrapVector, aPolyPolygon ); const int nTrapCount = aB2DTrapVector.size(); if( !nTrapCount ) return true; @@ -1654,7 +1660,12 @@ bool X11SalGraphicsImpl::drawPolyLine( for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) { const basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) ); - bDrawnOk = drawPolyPolygon( aOnePoly, fTransparency ); + + bDrawnOk = drawPolyPolygon( + basegfx::B2DHomMatrix(), + aOnePoly, + fTransparency); + if( !bDrawnOk ) break; } diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx index f738e1e996ea..ac80ec6f0c40 100644 --- a/vcl/unx/generic/gdi/gdiimpl.hxx +++ b/vcl/unx/generic/gdi/gdiimpl.hxx @@ -157,7 +157,11 @@ public: virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index c6eff6d45304..632d08d1a35b 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -577,14 +577,17 @@ css::uno::Any X11SalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rS #endif // ENABLE_CAIRO_CANVAS // draw a poly-polygon -bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency ) +bool X11SalGraphics::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) { if(fTransparency >= 1.0) { return true; } - const sal_uInt32 nPolyCount(rOrigPolyPoly.count()); + const sal_uInt32 nPolyCount(rPolyPolygon.count()); if(nPolyCount <= 0) { @@ -592,6 +595,10 @@ bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPo } #if ENABLE_CAIRO_CANVAS + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + if(SALCOLOR_NONE == mnFillColor && SALCOLOR_NONE == mnPenColor) { return true; @@ -602,12 +609,11 @@ bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPo if (!m_bOpenGL && bUseCairoForPolygons && SupportsCairo()) { // snap to raster if requested - basegfx::B2DPolyPolygon aPolyPoly(rOrigPolyPoly); const bool bSnapPoints(!getAntiAliasB2DDraw()); if(bSnapPoints) { - aPolyPoly = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPoly); + aPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygon); } cairo_t* cr = getCairoContext(); @@ -615,7 +621,7 @@ bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPo for(sal_uInt32 a(0); a < nPolyCount; ++a) { - const basegfx::B2DPolygon aPolygon(aPolyPoly.getB2DPolygon(a)); + const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(a)); const sal_uInt32 nPointCount(aPolygon.count()); if(nPointCount) @@ -684,7 +690,10 @@ bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPo } #endif // ENABLE_CAIRO_CANVAS - return mxImpl->drawPolyPolygon( rOrigPolyPoly, fTransparency ); + return mxImpl->drawPolyPolygon( + rObjectToDevice, + rPolyPolygon, + fTransparency); } #if ENABLE_CAIRO_CANVAS diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx index 4ee35c8b72eb..3a8f951ea03a 100644 --- a/vcl/unx/generic/print/genpspgraphics.cxx +++ b/vcl/unx/generic/print/genpspgraphics.cxx @@ -404,7 +404,10 @@ void GenPspGraphics::drawPolyPolygon( sal_uInt32 nPoly, m_pPrinterGfx->DrawPolyPolygon (nPoly, pPoints, reinterpret_cast<const Point**>(pPtAry)); } -bool GenPspGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon&, double /*fTransparency*/ ) +bool GenPspGraphics::drawPolyPolygon( + const basegfx::B2DHomMatrix& /*rObjectToDevice*/, + const basegfx::B2DPolyPolygon&, + double /*fTransparency*/) { // TODO: implement and advertise OutDevSupportType::B2DDraw support return false; diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index 33d89b6c94e1..4dcd86a4f405 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -1951,71 +1951,6 @@ void impAddB2DPolygonToGDIPlusGraphicsPathReal( } } -bool WinSalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) -{ - const sal_uInt32 nCount(rPolyPolygon.count()); - - if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0)) - { - Gdiplus::Graphics aGraphics(mrParent.getHDC()); - const sal_uInt8 aTrans(sal_uInt8(255) - static_cast<sal_uInt8>(basegfx::fround(fTransparency * 255.0))); - const Gdiplus::Color aTestColor(aTrans, maFillColor.GetRed(), maFillColor.GetGreen(), maFillColor.GetBlue()); - const Gdiplus::SolidBrush aSolidBrush(aTestColor.GetValue()); - Gdiplus::GraphicsPath aGraphicsPath(Gdiplus::FillModeAlternate); - - for(sal_uInt32 a(0); a < nCount; a++) - { - if(0 != a) - { - // #i101491# not needed for first run - aGraphicsPath.StartFigure(); - } - - impAddB2DPolygonToGDIPlusGraphicsPathReal( - aGraphicsPath, - rPolyPolygon.getB2DPolygon(a), - basegfx::B2DHomMatrix(), - false, - false); - - aGraphicsPath.CloseFigure(); - } - - if(mrParent.getAntiAliasB2DDraw()) - { - aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - } - else - { - aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone); - } - - if(mrParent.isPrinter()) - { - // #i121591# - // Normally GdiPlus should not be used for printing at all since printers cannot - // print transparent filled polygon geometry and normally this does not happen - // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation - // and no transparent parts should remain for printing. But this can be overridden - // by the user and thus happens. This call can only come (currently) from - // OutputDevice::DrawTransparent, see comments there with the same TaskID. - // If it is used, the mapping for the printer is wrong and needs to be corrected. I - // checked that there is *no* transformation set and estimated that a stable factor - // dependent of the printer's DPI is used. Create and set a transformation here to - // correct this. - const Gdiplus::REAL aDpiX(aGraphics.GetDpiX()); - const Gdiplus::REAL aDpiY(aGraphics.GetDpiY()); - - aGraphics.ResetTransform(); - aGraphics.ScaleTransform(Gdiplus::REAL(100.0) / aDpiX, Gdiplus::REAL(100.0) / aDpiY, Gdiplus::MatrixOrderAppend); - } - - aGraphics.FillPath(&aSolidBrush, &aGraphicsPath); - } - - return true; -} - class SystemDependentData_GraphicsPath : public basegfx::SystemDependentData { private: @@ -2040,6 +1975,150 @@ SystemDependentData_GraphicsPath::SystemDependentData_GraphicsPath( { } +bool WinSalGraphicsImpl::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) +{ + const sal_uInt32 nCount(rPolyPolygon.count()); + + if(!mbBrush || 0 == nCount || fTransparency < 0.0 || fTransparency > 1.0) + { + return true; + } + + Gdiplus::Graphics aGraphics(mrParent.getHDC()); + const sal_uInt8 aTrans(sal_uInt8(255) - static_cast<sal_uInt8>(basegfx::fround(fTransparency * 255.0))); + const Gdiplus::Color aTestColor(aTrans, maFillColor.GetRed(), maFillColor.GetGreen(), maFillColor.GetBlue()); + const Gdiplus::SolidBrush aSolidBrush(aTestColor.GetValue()); + + // Set full (Object-to-Device) transformation - if used + if(rObjectToDevice.isIdentity()) + { + aGraphics.ResetTransform(); + } + else + { + Gdiplus::Matrix aMatrix; + + aMatrix.SetElements( + rObjectToDevice.get(0, 0), + rObjectToDevice.get(1, 0), + rObjectToDevice.get(0, 1), + rObjectToDevice.get(1, 1), + rObjectToDevice.get(0, 2), + rObjectToDevice.get(1, 2)); + aGraphics.SetTransform(&aMatrix); + } + + // try to access buffered data + std::shared_ptr<SystemDependentData_GraphicsPath> pSystemDependentData_GraphicsPath( + rPolyPolygon.getSystemDependentData<SystemDependentData_GraphicsPath>()); + + if(!pSystemDependentData_GraphicsPath) + { + // add to buffering mechanism + pSystemDependentData_GraphicsPath = rPolyPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>( + ImplGetSystemDependentDataManager()); + + // Note: In principle we could use the same buffered geometry at line + // and fill polygons. Checked that in a first try, used + // GraphicsPath::AddPath from Gdiplus combined with below used + // StartFigure/CloseFigure, worked well (thus the line-draw version + // may create non-cloded partial Polygon data). + // + // But in current reality it gets not used due to e.g. + // SdrPathPrimitive2D::create2DDecomposition creating transformed + // line and fill polygon-primitives (what could be changed). + // + // There will probably be more hindrances here in other rendering paths + // which could all be found - intention to do this would be: Use more + // transformations, less modifications of B2DPolygons/B2DPolyPolygons. + // + // A fix for SdrPathPrimitive2D would be to create the sub-geometry + // and embed into a TransformPrimitive2D containing the transformation. + // + // A 2nd problem is that the NoLineJoin mode (basegfx::B2DLineJoin::NONE + // && rLineWidths > 0.0) creates polygon fill infos that are not reusable + // for the fill case (see ::drawPolyLine bnelow) - thus we would need a + // bool and/or two system-dependent paths buffered - doable, but complicated. + // + // All in all: Make B2DPolyPolygon a SystemDependentDataProvider and buffer + // the whole to-be-filled PolyPolygon independent from evtl. line-polygon + // (at least for now...) + + // create data + for(sal_uInt32 a(0); a < nCount; a++) + { + if(0 != a) + { + // #i101491# not needed for first run + pSystemDependentData_GraphicsPath->getGraphicsPath().StartFigure(); + } + + impAddB2DPolygonToGDIPlusGraphicsPathReal( + pSystemDependentData_GraphicsPath->getGraphicsPath(), + rPolyPolygon.getB2DPolygon(a), + rObjectToDevice, // not used due to the two 'false' values below, but to not forget later + false, + false); + + pSystemDependentData_GraphicsPath->getGraphicsPath().CloseFigure(); + } + } + + if(mrParent.getAntiAliasB2DDraw()) + { + aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); + } + else + { + aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone); + } + + if(mrParent.isPrinter()) + { + // #i121591# + // Normally GdiPlus should not be used for printing at all since printers cannot + // print transparent filled polygon geometry and normally this does not happen + // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation + // and no transparent parts should remain for printing. But this can be overridden + // by the user and thus happens. This call can only come (currently) from + // OutputDevice::DrawTransparent, see comments there with the same TaskID. + // If it is used, the mapping for the printer is wrong and needs to be corrected. I + // checked that there is *no* transformation set and estimated that a stable factor + // dependent of the printer's DPI is used. Create and set a transformation here to + // correct this. + const Gdiplus::REAL aDpiX(aGraphics.GetDpiX()); + const Gdiplus::REAL aDpiY(aGraphics.GetDpiY()); + + // Now the transformation maybe/is already used (see above), so do + // modify it without resetting to not destroy it. + // I double-checked with MS docu that Gdiplus::MatrixOrderAppend does what + // we need - in our notation, would be a multiply from left to execute + // current transform first and this scale last. + // I tried to trigger this code using Print from the menu and various + // targets, but got no hit, thus maybe obsolete anyways. If someone knows + // more, feel free to remove it. + // One more hint: This *may* also be needed now in ::drawPolyLine below + // since it also uses transformations now. + // + // aGraphics.ResetTransform(); + + aGraphics.ScaleTransform( + Gdiplus::REAL(100.0) / aDpiX, + Gdiplus::REAL(100.0) / aDpiY, + Gdiplus::MatrixOrderAppend); + } + + // use created or buffered data + aGraphics.FillPath( + &aSolidBrush, + &pSystemDependentData_GraphicsPath->getGraphicsPath()); + + return true; +} + bool WinSalGraphicsImpl::drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolygon, @@ -2062,15 +2141,24 @@ bool WinSalGraphicsImpl::drawPolyLine( bool bNoLineJoin(false); Gdiplus::Matrix aMatrix; - // Set full (Object-to-Device) transformation - aMatrix.SetElements( - rObjectToDevice.get(0, 0), - rObjectToDevice.get(1, 0), - rObjectToDevice.get(0, 1), - rObjectToDevice.get(1, 1), - rObjectToDevice.get(0, 2), - rObjectToDevice.get(1, 2)); - aGraphics.SetTransform(&aMatrix); + // Set full (Object-to-Device) transformation - if used + if(rObjectToDevice.isIdentity()) + { + aGraphics.ResetTransform(); + } + else + { + Gdiplus::Matrix aMatrix; + + aMatrix.SetElements( + rObjectToDevice.get(0, 0), + rObjectToDevice.get(1, 0), + rObjectToDevice.get(0, 1), + rObjectToDevice.get(1, 1), + rObjectToDevice.get(0, 2), + rObjectToDevice.get(1, 2)); + aGraphics.SetTransform(&aMatrix); + } switch(eLineJoin) { @@ -2145,7 +2233,7 @@ bool WinSalGraphicsImpl::drawPolyLine( { // add to buffering mechanism pSystemDependentData_GraphicsPath = rPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>( - SalGraphics::getSystemDependentDataManager()); + ImplGetSystemDependentDataManager()); // fill data of buffered data pSystemDependentData_GraphicsPath->setPixelSnapHairline(bPixelSnapHairline); diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx index 83d4125207a2..94a6de0e1e44 100644 --- a/vcl/win/gdi/gdiimpl.hxx +++ b/vcl/win/gdi/gdiimpl.hxx @@ -106,7 +106,11 @@ public: virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; - virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; virtual bool drawPolyLine( const basegfx::B2DHomMatrix& rObjectToDevice, diff --git a/vcl/win/gdi/salbmp.cxx b/vcl/win/gdi/salbmp.cxx index b61103e17067..664eedb6d269 100644 --- a/vcl/win/gdi/salbmp.cxx +++ b/vcl/win/gdi/salbmp.cxx @@ -146,7 +146,7 @@ std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinS { // add to buffering mechanism pSystemDependentData_GdiPlusBitmap = addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>( - SalGraphics::getSystemDependentDataManager()); + ImplGetSystemDependentDataManager()); // create and set data if(pAlphaSource) diff --git a/vcl/win/gdi/salgdi_gdiplus.cxx b/vcl/win/gdi/salgdi_gdiplus.cxx index 1f536e1843e6..99c7d0e506e9 100644 --- a/vcl/win/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/gdi/salgdi_gdiplus.cxx @@ -26,9 +26,15 @@ #include "gdiimpl.hxx" -bool WinSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) +bool WinSalGraphics::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) { - return mpImpl->drawPolyPolygon( rPolyPolygon, fTransparency ); + return mpImpl->drawPolyPolygon( + rObjectToDevice, + rPolyPolygon, + fTransparency); } bool WinSalGraphics::drawPolyLine( |