[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