diff options
author | Armin Le Grand <Armin.Le.Grand@cib.de> | 2018-08-24 13:01:08 +0200 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@cib.de> | 2018-08-30 19:48:46 +0200 |
commit | b9fa01a8d1137a95af9865a3e47995734c40da6e (patch) | |
tree | 6d1e0a3e44b1a96fe5302d779c00fbee55cf8d24 /vcl/win/gdi | |
parent | f4a9ce33415a85d0b86ced3a0bf780f4ec61e25f (diff) |
Support buffering SystemDependent GraphicData
This is a first step to allow buffering of system
dependent data, especially (but not only) for the
system-dependent implementations of graphic output.
For example, for B2DPolygon and Win output, it allows
buffering the Gdiplus::GraphicsPath instead of re-
creating it all the time.
To support that, the change includes forwarding the
current transformation to the renderers in SalGraphics.
The current state in VCL is to transform all and
everything to device coordinates at every single
paint.
I have currently started to do this for ::drawPolyLine
implementations. The fallbacks for all systems will
at the start of that method just transform the data
to device coordinates, so all works as before.
This may also be done for FilledPolygon paint in a later
step, but most urgent is FatLine painting.
An arrangement of shared_ptr/weak_ptr is used so that
either the instance buffering (in the example B2DPolygon)
or the instance managing it can delete it. The instance
managing it currently uses a 1s Timer and a cycle-lifetime
management, but that can be extended in the future
to e.g. include size hints, too.
The mechanism it designed to support multiple Data per
buffering element, e.g. for B2DPolygon at the same time
system-dependent instances of Gdiplus and Cairo can be
buffered, but also PDF-data.
This is achieved semi-automatic by using
typeid(class).hash_code() as key for organization.
The mechanism will be used for now at B2DPolygon, but
is not limited to. There is already a similar but less
general buffer (see GdiPlusBuffer) that can and will
be converted to use this new mechanism.
Added vcl/headless Cairo renderer to support given
ObjectToDevice transformation (not to transform given
B2DPolygon)
Added support for CairoPath buffered at B2DPolygon,
seems to work well. Need to do more tests
Moved usage to templates suggested by Noel Grandin
(Noel Grandin <noelgrandin@gmail.com>), thanks for
these suggestions. Adapted Win usage to that, too.
Converted Win-specific GdiPlus BitmapBuffer to new
mechanism, works well. Checked, the manager holds
now a mix of bitmap and path data under Win
Added a cleanup mechanism to flush all buffered data
at DeInitVCL() using flushAll() at
SystemDependentDataBuffer
Adapted Linux-versions of ::drawPolyLine to support
PixelSnapHairline, for now in a simplified version
that still allows buffering. This will also be used
(and use buffering) for the Cairo-fallback in
X11SalGraphics
Change-Id: I88d7e438a20b96ddab7707050893bdd590c098c7
Reviewed-on: https://gerrit.libreoffice.org/59555
Tested-by: Armin Le Grand <Armin.Le.Grand@cib.de>
Reviewed-by: Armin Le Grand <Armin.Le.Grand@cib.de>
Diffstat (limited to 'vcl/win/gdi')
-rw-r--r-- | vcl/win/gdi/gdiimpl.cxx | 280 | ||||
-rw-r--r-- | vcl/win/gdi/gdiimpl.hxx | 4 | ||||
-rw-r--r-- | vcl/win/gdi/salbmp.cxx | 219 | ||||
-rw-r--r-- | vcl/win/gdi/salgdi_gdiplus.cxx | 15 |
4 files changed, 291 insertions, 227 deletions
diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index a66f1f5f9579..bf2dcc9197e0 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -35,6 +35,7 @@ #include <vcl/salbtype.hxx> #include <win/salframe.h> #include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/utils/systemdependentdata.hxx> #include <outdata.hxx> #include <win/salids.hrc> @@ -1823,28 +1824,84 @@ bool WinSalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt return bRet; } +basegfx::B2DPoint impPixelSnap( + const basegfx::B2DPolygon& rPolygon, + const basegfx::B2DHomMatrix& rObjectToDevice, + basegfx::B2DHomMatrix& rObjectToDeviceInv, + sal_uInt32 nIndex) +{ + const sal_uInt32 nCount(rPolygon.count()); + + // get the data + const basegfx::B2ITuple aPrevTuple(basegfx::fround(rObjectToDevice * rPolygon.getB2DPoint((nIndex + nCount - 1) % nCount))); + const basegfx::B2DPoint aCurrPoint(rObjectToDevice * rPolygon.getB2DPoint(nIndex)); + const basegfx::B2ITuple aCurrTuple(basegfx::fround(aCurrPoint)); + const basegfx::B2ITuple aNextTuple(basegfx::fround(rObjectToDevice * rPolygon.getB2DPoint((nIndex + 1) % nCount))); + + // get the states + const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX()); + const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX()); + const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY()); + const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY()); + const bool bSnapX(bPrevVertical || bNextVertical); + const bool bSnapY(bPrevHorizontal || bNextHorizontal); + + if(bSnapX || bSnapY) + { + basegfx::B2DPoint aSnappedPoint( + bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(), + bSnapY ? aCurrTuple.getY() : aCurrPoint.getY()); + + if(rObjectToDeviceInv.isIdentity()) + { + rObjectToDeviceInv = rObjectToDevice; + rObjectToDeviceInv.invert(); + } + + aSnappedPoint *= rObjectToDeviceInv; + + return aSnappedPoint; + } + + return rPolygon.getB2DPoint(nIndex); +} + void impAddB2DPolygonToGDIPlusGraphicsPathReal( Gdiplus::GraphicsPath& rGraphicsPath, const basegfx::B2DPolygon& rPolygon, - bool bNoLineJoin) + const basegfx::B2DHomMatrix& rObjectToDevice, + bool bNoLineJoin, + bool bPixelSnapHairline) { sal_uInt32 nCount(rPolygon.count()); if(nCount) { const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); - const bool bControls(rPolygon.areControlPointsUsed()); - basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); if(nEdgeCount) { + const bool bControls(rPolygon.areControlPointsUsed()); + basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); + basegfx::B2DHomMatrix aObjectToDeviceInv; + + if(bPixelSnapHairline) + { + aCurr = impPixelSnap(rPolygon, rObjectToDevice, aObjectToDeviceInv, 0); + } + for(sal_uInt32 a(0); a < nEdgeCount; a++) { const sal_uInt32 nNextIndex((a + 1) % nCount); - const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); + basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); const bool b1stControlPointUsed(bControls && rPolygon.isNextControlPointUsed(a)); const bool b2ndControlPointUsed(bControls && rPolygon.isPrevControlPointUsed(nNextIndex)); + if(bPixelSnapHairline) + { + aNext = impPixelSnap(rPolygon, rObjectToDevice, aObjectToDeviceInv, nNextIndex); + } + if(b1stControlPointUsed || b2ndControlPointUsed) { basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); @@ -1914,7 +1971,12 @@ bool WinSalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPo aGraphicsPath.StartFigure(); } - impAddB2DPolygonToGDIPlusGraphicsPathReal(aGraphicsPath, rPolyPolygon.getB2DPolygon(a), false); + impAddB2DPolygonToGDIPlusGraphicsPathReal( + aGraphicsPath, + rPolyPolygon.getB2DPolygon(a), + basegfx::B2DHomMatrix(), + false, + false); aGraphicsPath.CloseFigure(); } @@ -1954,100 +2016,172 @@ bool WinSalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPo return true; } +class SystemDependentData_GraphicsPath : public basegfx::SystemDependentData +{ +private: + Gdiplus::GraphicsPath maGraphicsPath; + bool mbPixelSnapHairline; + +public: + SystemDependentData_GraphicsPath( + basegfx::SystemDependentDataManager& rSystemDependentDataManager); + virtual ~SystemDependentData_GraphicsPath() override; + + Gdiplus::GraphicsPath& getGraphicsPath() { return maGraphicsPath; } + + bool getPixelSnapHairline() const { return mbPixelSnapHairline; } + void setPixelSnapHairline(bool bNew) { mbPixelSnapHairline = bNew; } +}; + +SystemDependentData_GraphicsPath::SystemDependentData_GraphicsPath( + basegfx::SystemDependentDataManager& rSystemDependentDataManager) +: basegfx::SystemDependentData(rSystemDependentDataManager), + maGraphicsPath(), + mbPixelSnapHairline(false) +{ +} + +SystemDependentData_GraphicsPath::~SystemDependentData_GraphicsPath() +{ +} + bool WinSalGraphicsImpl::drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, - double fMiterMinimumAngle) + double fMiterMinimumAngle, + bool bPixelSnapHairline) { - const sal_uInt32 nCount(rPolygon.count()); - - if(mbPen && nCount) + if(!mbPen || 0 == rPolygon.count()) { - Gdiplus::Graphics aGraphics(mrParent.getHDC()); - const sal_uInt8 aTrans = static_cast<sal_uInt8>(basegfx::fround( 255 * (1.0 - fTransparency) )); - const Gdiplus::Color aTestColor(aTrans, maLineColor.GetRed(), maLineColor.GetGreen(), maLineColor.GetBlue()); - Gdiplus::Pen aPen(aTestColor.GetValue(), Gdiplus::REAL(rLineWidths.getX())); - Gdiplus::GraphicsPath aGraphicsPath(Gdiplus::FillModeAlternate); - bool bNoLineJoin(false); + return true; + } + + Gdiplus::Graphics aGraphics(mrParent.getHDC()); + const sal_uInt8 aTrans = static_cast<sal_uInt8>(basegfx::fround( 255 * (1.0 - fTransparency) )); + const Gdiplus::Color aTestColor(aTrans, maLineColor.GetRed(), maLineColor.GetGreen(), maLineColor.GetBlue()); + Gdiplus::Pen aPen(aTestColor.GetValue(), Gdiplus::REAL(rLineWidths.getX())); + bool bNoLineJoin(false); + Gdiplus::Matrix aMatrix; - switch(eLineJoin) + // 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); + + switch(eLineJoin) + { + case basegfx::B2DLineJoin::NONE : { - case basegfx::B2DLineJoin::NONE : - { - if(basegfx::fTools::more(rLineWidths.getX(), 0.0)) - { - bNoLineJoin = true; - } - break; - } - case basegfx::B2DLineJoin::Bevel : + if(basegfx::fTools::more(rLineWidths.getX(), 0.0)) { - aPen.SetLineJoin(Gdiplus::LineJoinBevel); - break; - } - case basegfx::B2DLineJoin::Miter : - { - const Gdiplus::REAL aMiterLimit(1.0/sin(fMiterMinimumAngle/2.0)); - - aPen.SetMiterLimit(aMiterLimit); - // tdf#99165 MS's LineJoinMiter creates non standard conform miter additional - // graphics, somewhere clipped in some distance from the edge point, dependent - // of MiterLimit. The more default-like option is LineJoinMiterClipped, so use - // that instead - aPen.SetLineJoin(Gdiplus::LineJoinMiterClipped); - break; - } - case basegfx::B2DLineJoin::Round : - { - aPen.SetLineJoin(Gdiplus::LineJoinRound); - break; + bNoLineJoin = true; } + break; } - - switch(eLineCap) + case basegfx::B2DLineJoin::Bevel : { - default: /*css::drawing::LineCap_BUTT*/ - { - // nothing to do - break; - } - case css::drawing::LineCap_ROUND: - { - aPen.SetStartCap(Gdiplus::LineCapRound); - aPen.SetEndCap(Gdiplus::LineCapRound); - break; - } - case css::drawing::LineCap_SQUARE: - { - aPen.SetStartCap(Gdiplus::LineCapSquare); - aPen.SetEndCap(Gdiplus::LineCapSquare); - break; - } + aPen.SetLineJoin(Gdiplus::LineJoinBevel); + break; } + case basegfx::B2DLineJoin::Miter : + { + const Gdiplus::REAL aMiterLimit(1.0/sin(fMiterMinimumAngle/2.0)); + + aPen.SetMiterLimit(aMiterLimit); + // tdf#99165 MS's LineJoinMiter creates non standard conform miter additional + // graphics, somewhere clipped in some distance from the edge point, dependent + // of MiterLimit. The more default-like option is LineJoinMiterClipped, so use + // that instead + aPen.SetLineJoin(Gdiplus::LineJoinMiterClipped); + break; + } + case basegfx::B2DLineJoin::Round : + { + aPen.SetLineJoin(Gdiplus::LineJoinRound); + break; + } + } - impAddB2DPolygonToGDIPlusGraphicsPathReal(aGraphicsPath, rPolygon, bNoLineJoin); - - if(rPolygon.isClosed() && !bNoLineJoin) + switch(eLineCap) + { + default: /*css::drawing::LineCap_BUTT*/ { - // #i101491# needed to create the correct line joins - aGraphicsPath.CloseFigure(); + // nothing to do + break; } + case css::drawing::LineCap_ROUND: + { + aPen.SetStartCap(Gdiplus::LineCapRound); + aPen.SetEndCap(Gdiplus::LineCapRound); + break; + } + case css::drawing::LineCap_SQUARE: + { + aPen.SetStartCap(Gdiplus::LineCapSquare); + aPen.SetEndCap(Gdiplus::LineCapSquare); + break; + } + } - if(mrParent.getAntiAliasB2DDraw()) + // try to access buffered data + std::shared_ptr<SystemDependentData_GraphicsPath> pSystemDependentData_GraphicsPath( + rPolygon.getSystemDependentData<SystemDependentData_GraphicsPath>()); + + if(pSystemDependentData_GraphicsPath) + { + // check data validity + if(pSystemDependentData_GraphicsPath->getPixelSnapHairline() != bPixelSnapHairline) { - aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); + // data invalid, forget + pSystemDependentData_GraphicsPath.reset(); } - else + } + + if(!pSystemDependentData_GraphicsPath) + { + // add to buffering mechanism + pSystemDependentData_GraphicsPath = rPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>( + SalGraphics::getSystemDependentDataManager()); + + // fill data of buffered data + pSystemDependentData_GraphicsPath->setPixelSnapHairline(bPixelSnapHairline); + + impAddB2DPolygonToGDIPlusGraphicsPathReal( + pSystemDependentData_GraphicsPath->getGraphicsPath(), + rPolygon, + rObjectToDevice, + bNoLineJoin, + bPixelSnapHairline); + + if(rPolygon.isClosed() && !bNoLineJoin) { - aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone); + // #i101491# needed to create the correct line joins + pSystemDependentData_GraphicsPath->getGraphicsPath().CloseFigure(); } + } - aGraphics.DrawPath(&aPen, &aGraphicsPath); + if(mrParent.getAntiAliasB2DDraw()) + { + aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); + } + else + { + aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone); } + aGraphics.DrawPath( + &aPen, + &pSystemDependentData_GraphicsPath->getGraphicsPath()); + return true; } diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx index 3bd39663aa9c..83d4125207a2 100644 --- a/vcl/win/gdi/gdiimpl.hxx +++ b/vcl/win/gdi/gdiimpl.hxx @@ -109,12 +109,14 @@ public: virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override; virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, css::drawing::LineCap, - double fMiterMinimumAngle) override; + double fMiterMinimumAngle, + bool bPixelSnapHairline) override; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, diff --git a/vcl/win/gdi/salbmp.cxx b/vcl/win/gdi/salbmp.cxx index 36bab849a316..fa8b011ab5aa 100644 --- a/vcl/win/gdi/salbmp.cxx +++ b/vcl/win/gdi/salbmp.cxx @@ -64,128 +64,12 @@ inline void ImplSetPixel4( sal_uInt8* pScanline, long nX, const BYTE cIndex ) } } -// Helper class to manage Gdiplus::Bitmap instances inside of -// WinSalBitmap - -typedef ::std::map< WinSalBitmap*, sal_uInt32 > EntryMap; -static const sal_uInt32 nDefaultCycles(60); - -class GdiPlusBuffer : protected cppu::BaseMutex, public Timer -{ -private: - EntryMap maEntries; - -public: - GdiPlusBuffer( const sal_Char *pDebugName ) - : Timer( pDebugName ), - maEntries() - { - SetTimeout(1000); - SetStatic(); - } - - ~GdiPlusBuffer() override - { - Stop(); - } - - void addEntry(WinSalBitmap& rEntry) - { - ::osl::MutexGuard aGuard(m_aMutex); - EntryMap::iterator aFound = maEntries.find(&rEntry); - - if(aFound == maEntries.end()) - { - if(maEntries.empty()) - { - Start(); - } - - maEntries[&rEntry] = nDefaultCycles; - } - } - - void remEntry(WinSalBitmap& rEntry) - { - ::osl::MutexGuard aGuard(m_aMutex); - EntryMap::iterator aFound = maEntries.find(&rEntry); - - if(aFound != maEntries.end()) - { - maEntries.erase(aFound); - - if(maEntries.empty()) - { - Stop(); - } - } - } - - void touchEntry(WinSalBitmap& rEntry) - { - ::osl::MutexGuard aGuard(m_aMutex); - EntryMap::iterator aFound = maEntries.find(&rEntry); - - if(aFound != maEntries.end()) - { - aFound->second = nDefaultCycles; - } - } - - // 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); - WinSalBitmap* pSource = aDelete->first; - ++aIter; - maEntries.erase(aDelete); - - if(maEntries.empty()) - { - Stop(); - } - - // delete at WinSalBitmap after entry is removed; this - // way it would not hurt to call remEntry from there, too - if(pSource->maGdiPlusBitmap.get()) - { - pSource->maGdiPlusBitmap.reset(); - pSource->mpAssociatedAlpha = nullptr; - } - } - } - - if(!maEntries.empty()) - { - Start(); - } - } -}; - -// Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap -// instances - -static GdiPlusBuffer aGdiPlusBuffer( "vcl::win GdiPlusBuffer aGdiPlusBuffer" ); - - WinSalBitmap::WinSalBitmap() -: maSize(), +: SalBitmap(), + basegfx::SystemDependentDataHolder(), + maSize(), mhDIB(nullptr), mhDDB(nullptr), - maGdiPlusBitmap(), - mpAssociatedAlpha(nullptr), mnBitCount(0) { } @@ -197,11 +81,6 @@ WinSalBitmap::~WinSalBitmap() void WinSalBitmap::Destroy() { - if(maGdiPlusBitmap.get()) - { - aGdiPlusBuffer.remEntry(*this); - } - if( mhDIB ) GlobalFree( mhDIB ); else if( mhDDB ) @@ -211,45 +90,85 @@ void WinSalBitmap::Destroy() mnBitCount = 0; } +class SystemDependentData_GdiPlusBitmap : public basegfx::SystemDependentData +{ +private: + std::shared_ptr<Gdiplus::Bitmap> mpGdiPlusBitmap; + const WinSalBitmap* mpAssociatedAlpha; + +public: + SystemDependentData_GdiPlusBitmap( + basegfx::SystemDependentDataManager& rSystemDependentDataManager); + virtual ~SystemDependentData_GdiPlusBitmap() override; + + const WinSalBitmap* getAssociatedAlpha() const { return mpAssociatedAlpha; } + void setAssociatedAlpha(const WinSalBitmap* pNew) { mpAssociatedAlpha = pNew; } + + const std::shared_ptr<Gdiplus::Bitmap>& getGdiPlusBitmap() const { return mpGdiPlusBitmap; } + void setGdiPlusBitmap(const std::shared_ptr<Gdiplus::Bitmap>& rNew) { mpGdiPlusBitmap = rNew; } +}; + +SystemDependentData_GdiPlusBitmap::SystemDependentData_GdiPlusBitmap( + basegfx::SystemDependentDataManager& rSystemDependentDataManager) +: basegfx::SystemDependentData(rSystemDependentDataManager), + mpGdiPlusBitmap(), + mpAssociatedAlpha(nullptr) +{ +} + +SystemDependentData_GdiPlusBitmap::~SystemDependentData_GdiPlusBitmap() +{ +} + std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const { - WinSalBitmap* pThat = const_cast< WinSalBitmap* >(this); + std::shared_ptr< Gdiplus::Bitmap > aRetval; + + // try to access buffered data + std::shared_ptr<SystemDependentData_GdiPlusBitmap> pSystemDependentData_GdiPlusBitmap( + getSystemDependentData<SystemDependentData_GdiPlusBitmap>()); - if(maGdiPlusBitmap.get() && pAlphaSource != mpAssociatedAlpha) + if(pSystemDependentData_GdiPlusBitmap) { - // #122350# if associated alpha with which the GDIPlus was constructed has changed - // it is necessary to remove it from buffer, reset reference to it and reconstruct - pThat->maGdiPlusBitmap.reset(); - aGdiPlusBuffer.remEntry(const_cast< WinSalBitmap& >(*this)); + // check data validity + if(pSystemDependentData_GdiPlusBitmap->getAssociatedAlpha() != pAlphaSource + || 0 == maSize.Width() + || 0 == maSize.Height()) + { + // #122350# if associated alpha with which the GDIPlus was constructed has changed + // it is necessary to remove it from buffer, reset reference to it and reconstruct + // data invalid, forget + pSystemDependentData_GdiPlusBitmap.reset(); + } } - if(maGdiPlusBitmap.get()) + if(pSystemDependentData_GdiPlusBitmap) { - aGdiPlusBuffer.touchEntry(const_cast< WinSalBitmap& >(*this)); + // use from buffer + aRetval = pSystemDependentData_GdiPlusBitmap->getGdiPlusBitmap(); } - else + else if(maSize.Width() > 0 && maSize.Height() > 0) { - if(maSize.Width() > 0 && maSize.Height() > 0) - { - if(pAlphaSource) - { - pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap(*pAlphaSource)); - pThat->mpAssociatedAlpha = pAlphaSource; - } - else - { - pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap()); - pThat->mpAssociatedAlpha = nullptr; - } + // add to buffering mechanism + pSystemDependentData_GdiPlusBitmap = addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>( + SalGraphics::getSystemDependentDataManager()); - if(maGdiPlusBitmap.get()) - { - aGdiPlusBuffer.addEntry(*pThat); - } + // create and set data + if(pAlphaSource) + { + aRetval.reset(const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource)); + pSystemDependentData_GdiPlusBitmap->setGdiPlusBitmap(aRetval); + pSystemDependentData_GdiPlusBitmap->setAssociatedAlpha(pAlphaSource); + } + else + { + aRetval.reset(const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap()); + pSystemDependentData_GdiPlusBitmap->setGdiPlusBitmap(aRetval); + pSystemDependentData_GdiPlusBitmap->setAssociatedAlpha(nullptr); } } - return maGdiPlusBitmap; + return aRetval; } Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap() diff --git a/vcl/win/gdi/salgdi_gdiplus.cxx b/vcl/win/gdi/salgdi_gdiplus.cxx index 45e760ae871b..1f536e1843e6 100644 --- a/vcl/win/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/gdi/salgdi_gdiplus.cxx @@ -32,15 +32,24 @@ bool WinSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygo } bool WinSalGraphics::drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, - double fMiterMinimumAngle) + double fMiterMinimumAngle, + bool bPixelSnapHairline) { - return mpImpl->drawPolyLine(rPolygon, fTransparency, rLineWidths, - eLineJoin, eLineCap, fMiterMinimumAngle); + return mpImpl->drawPolyLine( + rObjectToDevice, + rPolygon, + fTransparency, + rLineWidths, + eLineJoin, + eLineCap, + fMiterMinimumAngle, + bPixelSnapHairline); } bool WinSalGraphics::blendBitmap( |