[Libreoffice-commits] core.git: drawinglayer/source include/drawinglayer

Noel Grandin (via logerrit) logerrit at kemper.freedesktop.org
Fri Aug 27 06:48:51 UTC 2021


 drawinglayer/source/primitive2d/patternfillprimitive2d.cxx  |   45 +++++++
 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx     |   74 ++++++++++++
 drawinglayer/source/processor2d/vclpixelprocessor2d.hxx     |    2 
 include/drawinglayer/primitive2d/patternfillprimitive2d.hxx |   12 +
 4 files changed, 132 insertions(+), 1 deletion(-)

New commits:
commit 3cbe3a0259bea4dec70e72191ec3c03441926a07
Author:     Noel Grandin <noel.grandin at collabora.co.uk>
AuthorDate: Mon Jun 14 15:05:59 2021 +0200
Commit:     Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Fri Aug 27 08:48:19 2021 +0200

    tdf#101083 speed up SVG rendering with pattern fill
    
    By pushing the work down to the vcl layer, which has much more
    efficient ways of dump lots of copies of a single image
    
    Change-Id: Ie83fa56828df91a23b4b29934360ad80d1793c3f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117162
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
index e7a1f7480b6c..45776edc50d5 100644
--- a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
@@ -93,6 +93,30 @@ namespace drawinglayer::primitive2d
             }
         }
 
+        void PatternFillPrimitive2D::getTileSize(
+            sal_uInt32& rWidth,
+            sal_uInt32& rHeight,
+            const geometry::ViewInformation2D& rViewInformation) const
+        {
+            const basegfx::B2DRange aMaskRange(getMask().getB2DRange());
+
+            // get discrete rounded up square size of a single tile
+            const basegfx::B2DHomMatrix aMaskRangeTransformation(
+                basegfx::utils::createScaleTranslateB2DHomMatrix(
+                    aMaskRange.getRange(),
+                    aMaskRange.getMinimum()));
+            const basegfx::B2DHomMatrix aTransform(
+                rViewInformation.getObjectToViewTransformation() * aMaskRangeTransformation);
+            const basegfx::B2DPoint aTopLeft(aTransform * getReferenceRange().getMinimum());
+            const basegfx::B2DPoint aX(aTransform * basegfx::B2DPoint(getReferenceRange().getMaxX(), getReferenceRange().getMinY()));
+            const basegfx::B2DPoint aY(aTransform * basegfx::B2DPoint(getReferenceRange().getMinX(), getReferenceRange().getMaxY()));
+            const double fW(basegfx::B2DVector(aX - aTopLeft).getLength());
+            const double fH(basegfx::B2DVector(aY - aTopLeft).getLength());
+
+            rWidth = basegfx::fround(ceil(fW));
+            rHeight = basegfx::fround(ceil(fH));
+        }
+
         Primitive2DContainer PatternFillPrimitive2D::createContent(const geometry::ViewInformation2D& rViewInformation) const
         {
             Primitive2DContainer aContent;
@@ -142,7 +166,7 @@ namespace drawinglayer::primitive2d
 
                 // check if content needs to be clipped
                 const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
-                const basegfx::B2DRange aContentRange(getChildren().getB2DRange(rViewInformation));
+                const basegfx::B2DRange aContentRange(aContent.getB2DRange(rViewInformation));
 
                 if(!aUnitRange.isInside(aContentRange))
                 {
@@ -158,6 +182,25 @@ namespace drawinglayer::primitive2d
             return aContent;
         }
 
+        //  create buffered content in given resolution
+        BitmapEx PatternFillPrimitive2D::createTileImage(sal_uInt32 nWidth, sal_uInt32 nHeight) const
+        {
+            const geometry::ViewInformation2D aViewInformation2D;
+            const Primitive2DContainer aContent(createContent(aViewInformation2D));
+            const primitive2d::Primitive2DReference xEmbedRef(
+                    new primitive2d::TransformPrimitive2D(
+                        basegfx::utils::createScaleB2DHomMatrix(nWidth, nHeight),
+                        aContent));
+            const primitive2d::Primitive2DContainer xEmbedSeq { xEmbedRef };
+
+            return convertToBitmapEx(
+                        xEmbedSeq,
+                        aViewInformation2D,
+                        nWidth,
+                        nHeight,
+                        nWidth * nHeight);
+        }
+
         void PatternFillPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const
         {
             Primitive2DContainer aRetval;
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 4e9e963ef065..58f5f2881402 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -27,7 +27,9 @@
 #include <vcl/BitmapFilterStackBlur.hxx>
 #include <vcl/outdev.hxx>
 #include <vcl/hatch.hxx>
+#include <vcl/canvastools.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
 
 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
 #include <drawinglayer/primitive2d/Tools.hxx>
@@ -57,6 +59,7 @@
 #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
 #include <drawinglayer/primitive2d/softedgeprimitive2d.hxx>
 #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
+#include <drawinglayer/primitive2d/patternfillprimitive2d.hxx>
 
 #include <com/sun/star/awt/XWindow2.hpp>
 #include <com/sun/star/awt/XControl.hpp>
@@ -427,6 +430,12 @@ void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv
                 static_cast<const drawinglayer::primitive2d::FillGradientPrimitive2D&>(rCandidate));
             break;
         }
+        case PRIMITIVE2D_ID_PATTERNFILLPRIMITIVE2D:
+        {
+            processPatternFillPrimitive2D(
+                static_cast<const drawinglayer::primitive2d::PatternFillPrimitive2D&>(rCandidate));
+            break;
+        }
         default:
         {
             SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(
@@ -1231,6 +1240,71 @@ void VclPixelProcessor2D::processFillGradientPrimitive2D(
     mpOutputDevice->Pop();
 }
 
+void VclPixelProcessor2D::processPatternFillPrimitive2D(
+    const primitive2d::PatternFillPrimitive2D& rPrimitive)
+{
+    const basegfx::B2DRange& rReferenceRange = rPrimitive.getReferenceRange();
+    if (rReferenceRange.isEmpty() || rReferenceRange.getWidth() <= 0.0
+        || rReferenceRange.getHeight() <= 0.0)
+        return;
+
+    basegfx::B2DPolyPolygon aMask = rPrimitive.getMask();
+    aMask.transform(maCurrentTransformation);
+    const basegfx::B2DRange aMaskRange(aMask.getB2DRange());
+
+    if (aMaskRange.isEmpty() || aMaskRange.getWidth() <= 0.0 || aMaskRange.getHeight() <= 0.0)
+        return;
+
+    sal_uInt32 nTileWidth, nTileHeight;
+    rPrimitive.getTileSize(nTileWidth, nTileHeight, getViewInformation2D());
+    if (nTileWidth == 0 || nTileHeight == 0)
+        return;
+    BitmapEx aTileImage = rPrimitive.createTileImage(nTileWidth, nTileHeight);
+    tools::Rectangle aMaskRect = vcl::unotools::rectangleFromB2DRectangle(aMaskRange);
+
+    // Unless smooth edges are needed, simply use clipping.
+    if (basegfx::utils::isRectangle(aMask) || !SvtOptionsDrawinglayer::IsAntiAliasing())
+    {
+        mpOutputDevice->Push(PushFlags::CLIPREGION);
+        mpOutputDevice->IntersectClipRegion(vcl::Region(aMask));
+        mpOutputDevice->DrawWallpaper(aMaskRect, Wallpaper(aTileImage));
+        mpOutputDevice->Pop();
+        return;
+    }
+
+    impBufferDevice aBufferDevice(*mpOutputDevice, aMaskRange);
+
+    if (!aBufferDevice.isVisible())
+        return;
+
+    // remember last OutDev and set to content
+    OutputDevice* pLastOutputDevice = mpOutputDevice;
+    mpOutputDevice = &aBufferDevice.getContent();
+
+    // if the tile is a single pixel big, just flood fill with that pixel color
+    if (nTileWidth == 1 && nTileHeight == 1)
+    {
+        Color col = aTileImage.GetPixelColor(0, 0);
+        mpOutputDevice->SetLineColor(col);
+        mpOutputDevice->SetFillColor(col);
+        mpOutputDevice->DrawRect(aMaskRect);
+    }
+    else
+        mpOutputDevice->DrawWallpaper(aMaskRect, Wallpaper(aTileImage));
+
+    // back to old OutDev
+    mpOutputDevice = pLastOutputDevice;
+
+    // draw mask
+    VirtualDevice& rMask = aBufferDevice.getTransparence();
+    rMask.SetLineColor();
+    rMask.SetFillColor(COL_BLACK);
+    rMask.DrawPolyPolygon(aMask);
+
+    // dump buffer to outdev
+    aBufferDevice.paint();
+}
+
 } // end of namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
index 480fdcaa6e18..eaf212c8e5b1 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
@@ -43,6 +43,7 @@ class GlowPrimitive2D;
 class ShadowPrimitive2D;
 class SoftEdgePrimitive2D;
 class FillGradientPrimitive2D;
+class PatternFillPrimitive2D;
 }
 
 namespace drawinglayer::processor2d
@@ -101,6 +102,7 @@ class VclPixelProcessor2D final : public VclProcessor2D
     void processSoftEdgePrimitive2D(const primitive2d::SoftEdgePrimitive2D& rCandidate);
     void processShadowPrimitive2D(const primitive2d::ShadowPrimitive2D& rCandidate);
     void processFillGradientPrimitive2D(const primitive2d::FillGradientPrimitive2D& rPrimitive);
+    void processPatternFillPrimitive2D(const primitive2d::PatternFillPrimitive2D& rPrimitive);
 
 public:
     /// constructor/destructor
diff --git a/include/drawinglayer/primitive2d/patternfillprimitive2d.hxx b/include/drawinglayer/primitive2d/patternfillprimitive2d.hxx
index 9220209306b0..f9c183f41ad6 100644
--- a/include/drawinglayer/primitive2d/patternfillprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/patternfillprimitive2d.hxx
@@ -22,6 +22,7 @@
 #include <drawinglayer/drawinglayerdllapi.h>
 #include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
 #include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <vcl/bitmapex.hxx>
 
 
 namespace drawinglayer::primitive2d
@@ -85,6 +86,17 @@ namespace drawinglayer::primitive2d
 
             // XAccounting
             virtual sal_Int64 SAL_CALL estimateUsage() override;
+
+            /// helper which creates the content - checks if clipping is needed and eventually
+            /// creates buffered content to speed up rendering
+            BitmapEx createTileImage(sal_uInt32 nWidth, sal_uInt32 nHeight) const;
+
+            /// helper that is capable to calculate the needed discrete buffer size for
+            /// eventually buffered content
+            void getTileSize(
+                sal_uInt32& rWidth,
+                sal_uInt32& rHeight,
+                const geometry::ViewInformation2D& rViewInformation) const;
         };
 } // end of namespace drawinglayer::primitive2d
 


More information about the Libreoffice-commits mailing list