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>
diff --git a/basegfx/source/polygon/b2dpolygon.cxx b/basegfx/source/polygon/b2dpolygon.cxx
index c94f262..3638424 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 a1ac530..0901eaf 100644
--- a/basegfx/source/polygon/b2dpolypolygon.cxx
+++ b/basegfx/source/polygon/b2dpolypolygon.cxx
@@ -22,24 +22,65 @@
#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 basegfx::B2DPolygon& rToBeCopied) :
maPolygons(1,rToBeCopied)
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);
}
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
{
// same polygon count?
@@ -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 3295a97..002ae53 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 fff49fb..65e3b97 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 f015f52..13ac5a5d 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 5615003..af3fa0a 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 5acd288..56bd740 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);
setupPolyPolygon(cr, rPolyPoly);
// 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);
}
// 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 158c331..9c7ee03 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 f2fd9b7..bc19dcd 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 6bde41f..76c3914 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 b03fa5b..24b5268 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 31c4848..19fac92 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 8e545d0..d4023bd 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 679debc..6ef2795 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 3f6bae6..bddcb88 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 8b73c45..d6054ea 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 9f30f57..e8fe72c 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 4c966bd..082c8d6 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 3b8d2ee..f8ab00e 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 09adf78..59d8365 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 93fcfec..9e5c3bc 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 ce3ed13..251da9e 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 beed242..b4cfa73 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 d39bd33..d28c751 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 fe16d67..fecacba 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 94ad52a..1496b1a 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 b5c06b9..da8be42 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 ecd63b6..5a9bd59 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 );
}
bool bDrawnOk = true;
// create ObjectToDevice transformation
const basegfx::B2DHomMatrix aFullTransform(ImplGetDeviceTransformation() * rObjectTransform);
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 c650f9d..a5fcf86 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 f738e1e..ac80ec6 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 c6eff6d..632d08d 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 4ee35c8..3a8f951 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 33d89b6..4dcd86a 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 83d4125..94a6de0 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 b61103e..664eedb 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 1f536e1..99c7d0e 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(