summaryrefslogtreecommitdiff
path: root/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer/source/primitive2d/patternfillprimitive2d.cxx')
-rw-r--r--drawinglayer/source/primitive2d/patternfillprimitive2d.cxx205
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)