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 /vcl/win | |
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>
Diffstat (limited to 'vcl/win')
-rw-r--r-- | vcl/win/gdi/gdiimpl.cxx | 238 | ||||
-rw-r--r-- | vcl/win/gdi/gdiimpl.hxx | 6 | ||||
-rw-r--r-- | vcl/win/gdi/salbmp.cxx | 2 | ||||
-rw-r--r-- | vcl/win/gdi/salgdi_gdiplus.cxx | 10 |
4 files changed, 177 insertions, 79 deletions
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( |