diff options
author | Armin Le Grand <Armin.Le.Grand@cib.de> | 2016-07-01 15:40:00 +0200 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2016-07-07 22:32:39 +0200 |
commit | 4609380bb0bde0d4437b72b752c1c24ee2950361 (patch) | |
tree | d5083eb62aa8f5717997274cecf4011e8f5b8126 /drawinglayer/source/primitive2d | |
parent | c1f476d91805e6a9573bba3ea8f5f980e0ea7b54 (diff) |
tdf#82214 optimize performance for primitives
See svg bug doc, which is processed quite slowly. Beyond needing faster
renderers, there is also demand to improve the handling of primitives
created by SVG import.
Conflicts:
drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
vcl/win/gdi/gdiimpl.cxx
Change-Id: I10992a5746b8b2d6b50e3ee3fe415a035685c9ba
Diffstat (limited to 'drawinglayer/source/primitive2d')
-rw-r--r-- | drawinglayer/source/primitive2d/patternfillprimitive2d.cxx | 205 |
1 files changed, 189 insertions, 16 deletions
diff --git a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx index ff3e4452886b..39b695c4be7a 100644 --- a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx @@ -21,19 +21,144 @@ #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> #include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <drawinglayer/texture/texture.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> - +#include <drawinglayer/tools/converters.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> using namespace com::sun::star; +#define MAXIMUM_SQUARE_LENGTH (164.0) +#define MINIMUM_SQUARE_LENGTH (32.0) +#define MINIMUM_TILES_LENGTH (3) namespace drawinglayer { namespace primitive2d { + void PatternFillPrimitive2D::calculateNeededDiscreteBufferSize( + sal_uInt32& rWidth, + sal_uInt32& rHeight, + const geometry::ViewInformation2D& rViewInformation) const + { + // reset parameters + rWidth = rHeight = 0; + + // check if resolution is in the range which may be buffered + const basegfx::B2DPolyPolygon& rMaskPolygon = getMask(); + const basegfx::B2DRange aMaskRange(rMaskPolygon.getB2DRange()); + + // get discrete rounded up square size of a single tile + const basegfx::B2DHomMatrix aMaskRangeTransformation( + basegfx::tools::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()); + const double fSquare(fW * fH); + + if(fSquare > 0.0) + { + // check if less than a maximum square pixels is used + static sal_uInt32 fMaximumSquare(MAXIMUM_SQUARE_LENGTH * MAXIMUM_SQUARE_LENGTH); + + if(fSquare < fMaximumSquare) + { + // calculate needed number of tiles and check if used more than a minimum count + const texture::GeoTexSvxTiled aTiling(getReferenceRange()); + const sal_uInt32 nTiles(aTiling.getNumberOfTiles()); + static sal_uInt32 nMinimumTiles(MINIMUM_TILES_LENGTH * MINIMUM_TILES_LENGTH); + + if(nTiles >= nMinimumTiles) + { + rWidth = basegfx::fround(ceil(fW)); + rHeight = basegfx::fround(ceil(fH)); + static sal_uInt32 fMinimumSquare(MINIMUM_SQUARE_LENGTH * MINIMUM_SQUARE_LENGTH); + + if(fSquare < fMinimumSquare) + { + const double fRel(fW/fH); + rWidth = basegfx::fround(sqrt(fMinimumSquare * fRel)); + rHeight = basegfx::fround(sqrt(fMinimumSquare / fRel)); + } + } + } + } + } + + Primitive2DContainer PatternFillPrimitive2D::createContent(const geometry::ViewInformation2D& rViewInformation) const + { + Primitive2DContainer aContent; + + // see if buffering is wanted. it is wanted, create buffered content in given resolution + if(0 != mnDiscreteWidth && 0 != mnDiscreteHeight) + { + const geometry::ViewInformation2D aViewInformation2D; + const primitive2d::Primitive2DReference xEmbedRef( + new primitive2d::TransformPrimitive2D( + basegfx::tools::createScaleB2DHomMatrix(mnDiscreteWidth, mnDiscreteHeight), + getChildren())); + const primitive2d::Primitive2DContainer xEmbedSeq { xEmbedRef }; + + const BitmapEx aBitmapEx( + tools::convertToBitmapEx( + xEmbedSeq, + aViewInformation2D, + mnDiscreteWidth, + mnDiscreteHeight, + mnDiscreteWidth * mnDiscreteHeight)); + + if(!aBitmapEx.IsEmpty()) + { + const Size& rBmpPix = aBitmapEx.GetSizePixel(); + + if(rBmpPix.Width() > 0 && rBmpPix.Height() > 0) + { + const primitive2d::Primitive2DReference xEmbedRefBitmap( + new primitive2d::BitmapPrimitive2D( + aBitmapEx, + basegfx::B2DHomMatrix())); + aContent = primitive2d::Primitive2DContainer { xEmbedRefBitmap }; + } + } + } + + if(aContent.empty()) + { + // buffering was not tried or did fail - reset remembered buffered size + // in any case + PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this); + pThat->mnDiscreteWidth = pThat->mnDiscreteHeight = 0; + + // use children as default context + aContent = getChildren(); + + // 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)); + + if(!aUnitRange.isInside(aContentRange)) + { + const Primitive2DReference xRef( + new MaskPrimitive2D( + basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aUnitRange)), + aContent)); + + aContent = Primitive2DContainer { xRef }; + } + } + + return aContent; + } + Primitive2DContainer PatternFillPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const { Primitive2DContainer aRetval; @@ -52,20 +177,8 @@ namespace drawinglayer aTiling.appendTransformations(aMatrices); - // 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)); - Primitive2DContainer aContent(getChildren()); - - if(!aUnitRange.isInside(aContentRange)) - { - const Primitive2DReference xRef( - new MaskPrimitive2D( - basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aUnitRange)), - aContent)); - - aContent = Primitive2DContainer { xRef }; - } + // create content + const Primitive2DContainer aContent(createContent(rViewInformation)); // resize result aRetval.resize(aMatrices.size()); @@ -117,7 +230,9 @@ namespace drawinglayer : BufferedDecompositionPrimitive2D(), maMask(rMask), maChildren(rChildren), - maReferenceRange(rReferenceRange) + maReferenceRange(rReferenceRange), + mnDiscreteWidth(0), + mnDiscreteHeight(0) { } @@ -140,6 +255,64 @@ namespace drawinglayer return getMask().getB2DRange(); } + Primitive2DContainer PatternFillPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + if(0 == mnDiscreteWidth || 0 == mnDiscreteHeight) + { + // Currently no buffering is used. Check if the resulting discrete sizes + // in the current situation would be good for buffering from now on + PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this); + + calculateNeededDiscreteBufferSize(pThat->mnDiscreteWidth, pThat->mnDiscreteHeight, rViewInformation); + } + else + { + // The existing bufferd decomposition uses a buffer in the remembered + // size. Get new needed sizes which depend on the given ViewInformation + sal_uInt32 nW(0); + sal_uInt32 nH(0); + calculateNeededDiscreteBufferSize(nW, nH, rViewInformation); + + if(0 != nW && 0 != nH) + { + // buffering is possible - check if reset is needed + bool bResetBuffering = false; + + if(nW > mnDiscreteWidth || nH > mnDiscreteHeight) + { + // Higher resolution is needed than used in the existing buffered + // decomposition + bResetBuffering = true; + } + else if(double(nW * nH) / double(mnDiscreteWidth * mnDiscreteHeight) <= 0.5) + { + // Size has shrunk for 50% or more - it's worth to refresh the buffering + bResetBuffering = true; + } + + if(bResetBuffering) + { + PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this); + pThat->mnDiscreteWidth = nW; + pThat->mnDiscreteHeight = nH; + pThat->setBuffered2DDecomposition(Primitive2DContainer()); + } + } + else + { + // no buffering wanted or possible - clear decomposition to create a + // new, unbuffered one + PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this); + pThat->mnDiscreteWidth = 0; + pThat->mnDiscreteHeight = 0; + pThat->setBuffered2DDecomposition(Primitive2DContainer()); + } + } + + // call parent + return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation); + } + // provide unique ID ImplPrimitive2DIDBlock(PatternFillPrimitive2D, PRIMITIVE2D_ID_PATTERNFILLPRIMITIVE2D) |