diff options
Diffstat (limited to 'drawinglayer/source/primitive2d/patternfillprimitive2d.cxx')
-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) |