vcl/headless/CairoCommon.cxx     |   45 +++++++++++++++++++++++++--------------
 vcl/inc/headless/CairoCommon.hxx |   15 +++++++++----
 2 files changed, 40 insertions(+), 20 deletions(-)

New commits:
commit 7be8430702d433ce981d65fdf12e510c1cddda53
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Wed May 17 15:56:10 2023 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Thu May 18 09:16:22 2023 +0200

    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.gran...@collabora.co.uk>

diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx
index d9c77afa1e56..9c67fb079566 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 6d280d34a955..f7556ede27ae 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);

Reply via email to