tdf#63130 reduce duplicated work when pixel snapping
Cache the calculations so we don't repeat work unnecessarily. Shaves 5%
off load time.
Change-Id: Iffbdd08768fea5b25ac83926b812067f52cba3a2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151883
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx
index d9c77af..9c67fb0 100644
--- a/vcl/headless/CairoCommon.cxx
+++ b/vcl/headless/CairoCommon.cxx
@@ -160,6 +160,7 @@ size_t AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rPolygon,
const bool bObjectToDeviceUsed(!rObjectToDevice.isIdentity());
basegfx::B2DHomMatrix aObjectToDeviceInv;
basegfx::B2DPoint aLast;
PixelSnapper aSnapper;
for (sal_uInt32 nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++)
{
@@ -209,7 +210,7 @@ size_t AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rPolygon,
{
// snap horizontal and vertical lines (mainly used in Chart for
// 'nicer' AAing)
aPoint = impPixelSnap(rPolygon, rObjectToDevice, aObjectToDeviceInv, nClosedIdx);
aPoint = aSnapper.snap(rPolygon, rObjectToDevice, aObjectToDeviceInv, nClosedIdx);
}
if (!nPointIdx)
@@ -271,32 +272,44 @@ size_t AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rPolygon,
return nSizeMeasure;
}
basegfx::B2DPoint impPixelSnap(const basegfx::B2DPolygon& rPolygon,
const basegfx::B2DHomMatrix& rObjectToDevice,
basegfx::B2DHomMatrix& rObjectToDeviceInv, sal_uInt32 nIndex)
basegfx::B2DPoint PixelSnapper::snap(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)));
if (nIndex == 0)
{
// if it's the first time, we need to calculate everything
maPrevPoint = rObjectToDevice * rPolygon.getB2DPoint((nIndex + nCount - 1) % nCount);
maCurrPoint = rObjectToDevice * rPolygon.getB2DPoint(nIndex);
maPrevTuple = basegfx::fround(maPrevPoint);
maCurrTuple = basegfx::fround(maCurrPoint);
}
else
{
// but for all other times, we can re-use the previous iteration computations
maPrevPoint = maCurrPoint;
maPrevTuple = maCurrTuple;
maCurrPoint = maNextPoint;
maCurrTuple = maNextTuple;
}
maNextPoint = rObjectToDevice * rPolygon.getB2DPoint((nIndex + 1) % nCount);
maNextTuple = basegfx::fround(maNextPoint);
// 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 bPrevVertical(maPrevTuple.getX() == maCurrTuple.getX());
const bool bNextVertical(maNextTuple.getX() == maCurrTuple.getX());
const bool bPrevHorizontal(maPrevTuple.getY() == maCurrTuple.getY());
const bool bNextHorizontal(maNextTuple.getY() == maCurrTuple.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());
basegfx::B2DPoint aSnappedPoint(bSnapX ? maCurrTuple.getX() : maCurrPoint.getX(),
bSnapY ? maCurrTuple.getY() : maCurrPoint.getY());
if (rObjectToDeviceInv.isIdentity())
{
diff --git a/vcl/inc/headless/CairoCommon.hxx b/vcl/inc/headless/CairoCommon.hxx
index 6d280d3..f7556ed 100644
--- a/vcl/inc/headless/CairoCommon.hxx
+++ b/vcl/inc/headless/CairoCommon.hxx
@@ -91,10 +91,17 @@ VCL_DLLPUBLIC size_t AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rP
const basegfx::B2DHomMatrix& rObjectToDevice, bool bPixelSnap,
bool bPixelSnapHairline);
VCL_DLLPUBLIC basegfx::B2DPoint impPixelSnap(const basegfx::B2DPolygon& rPolygon,
const basegfx::B2DHomMatrix& rObjectToDevice,
basegfx::B2DHomMatrix& rObjectToDeviceInv,
sal_uInt32 nIndex);
class VCL_DLLPUBLIC PixelSnapper
{
public:
basegfx::B2DPoint snap(const basegfx::B2DPolygon& rPolygon,
const basegfx::B2DHomMatrix& rObjectToDevice,
basegfx::B2DHomMatrix& rObjectToDeviceInv, sal_uInt32 nIndex);
private:
basegfx::B2DPoint maPrevPoint, maCurrPoint, maNextPoint;
basegfx::B2ITuple maPrevTuple, maCurrTuple, maNextTuple;
};
VCL_DLLPUBLIC void add_polygon_path(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPolygon,
const basegfx::B2DHomMatrix& rObjectToDevice, bool bPixelSnap);