nss: upgrade to release 3.73
[LibreOffice.git] / drawinglayer / source / primitive2d / patternfillprimitive2d.cxx
blobec1f9621452ad492ab748ca29a77066cbc3d42e4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <drawinglayer/primitive2d/patternfillprimitive2d.hxx>
21 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
22 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
23 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 #include <texture/texture.hxx>
27 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
28 #include <drawinglayer/geometry/viewinformation2d.hxx>
29 #include <toolkit/helper/vclunohelper.hxx>
31 #include <converters.hxx>
33 using namespace com::sun::star;
35 #define MAXIMUM_SQUARE_LENGTH (186.0)
36 #define MINIMUM_SQUARE_LENGTH (16.0)
37 #define MINIMUM_TILES_LENGTH (3)
39 namespace drawinglayer::primitive2d
41 void PatternFillPrimitive2D::calculateNeededDiscreteBufferSize(
42 sal_uInt32& rWidth,
43 sal_uInt32& rHeight,
44 const geometry::ViewInformation2D& rViewInformation) const
46 // reset parameters
47 rWidth = rHeight = 0;
49 // check if resolution is in the range which may be buffered
50 const basegfx::B2DPolyPolygon& rMaskPolygon = getMask();
51 const basegfx::B2DRange aMaskRange(rMaskPolygon.getB2DRange());
53 // get discrete rounded up square size of a single tile
54 const basegfx::B2DHomMatrix aMaskRangeTransformation(
55 basegfx::utils::createScaleTranslateB2DHomMatrix(
56 aMaskRange.getRange(),
57 aMaskRange.getMinimum()));
58 const basegfx::B2DHomMatrix aTransform(
59 rViewInformation.getObjectToViewTransformation() * aMaskRangeTransformation);
60 const basegfx::B2DPoint aTopLeft(aTransform * getReferenceRange().getMinimum());
61 const basegfx::B2DPoint aX(aTransform * basegfx::B2DPoint(getReferenceRange().getMaxX(), getReferenceRange().getMinY()));
62 const basegfx::B2DPoint aY(aTransform * basegfx::B2DPoint(getReferenceRange().getMinX(), getReferenceRange().getMaxY()));
63 const double fW(basegfx::B2DVector(aX - aTopLeft).getLength());
64 const double fH(basegfx::B2DVector(aY - aTopLeft).getLength());
65 const double fSquare(fW * fH);
67 if(fSquare <= 0.0)
68 return;
70 // check if less than a maximum square pixels is used
71 static const sal_uInt32 fMaximumSquare(MAXIMUM_SQUARE_LENGTH * MAXIMUM_SQUARE_LENGTH);
73 if(fSquare >= fMaximumSquare)
74 return;
76 // calculate needed number of tiles and check if used more than a minimum count
77 const texture::GeoTexSvxTiled aTiling(getReferenceRange());
78 const sal_uInt32 nTiles(aTiling.getNumberOfTiles());
79 static const sal_uInt32 nMinimumTiles(MINIMUM_TILES_LENGTH * MINIMUM_TILES_LENGTH);
81 if(nTiles < nMinimumTiles)
82 return;
84 rWidth = basegfx::fround(ceil(fW));
85 rHeight = basegfx::fround(ceil(fH));
86 static const sal_uInt32 fMinimumSquare(MINIMUM_SQUARE_LENGTH * MINIMUM_SQUARE_LENGTH);
88 if(fSquare < fMinimumSquare)
90 const double fRel(fW/fH);
91 rWidth = basegfx::fround(sqrt(fMinimumSquare * fRel));
92 rHeight = basegfx::fround(sqrt(fMinimumSquare / fRel));
96 Primitive2DContainer PatternFillPrimitive2D::createContent(const geometry::ViewInformation2D& rViewInformation) const
98 Primitive2DContainer aContent;
100 // see if buffering is wanted. If so, create buffered content in given resolution
101 if(0 != mnDiscreteWidth && 0 != mnDiscreteHeight)
103 const geometry::ViewInformation2D aViewInformation2D;
104 const primitive2d::Primitive2DReference xEmbedRef(
105 new primitive2d::TransformPrimitive2D(
106 basegfx::utils::createScaleB2DHomMatrix(mnDiscreteWidth, mnDiscreteHeight),
107 getChildren()));
108 const primitive2d::Primitive2DContainer xEmbedSeq { xEmbedRef };
110 const BitmapEx aBitmapEx(
111 convertToBitmapEx(
112 xEmbedSeq,
113 aViewInformation2D,
114 mnDiscreteWidth,
115 mnDiscreteHeight,
116 mnDiscreteWidth * mnDiscreteHeight));
118 if(!aBitmapEx.IsEmpty())
120 const Size& rBmpPix = aBitmapEx.GetSizePixel();
122 if(rBmpPix.Width() > 0 && rBmpPix.Height() > 0)
124 const primitive2d::Primitive2DReference xEmbedRefBitmap(
125 new primitive2d::BitmapPrimitive2D(
126 VCLUnoHelper::CreateVCLXBitmap(aBitmapEx),
127 basegfx::B2DHomMatrix()));
128 aContent = primitive2d::Primitive2DContainer { xEmbedRefBitmap };
133 if(aContent.empty())
135 // buffering was not tried or did fail - reset remembered buffered size
136 // in any case
137 PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this);
138 pThat->mnDiscreteWidth = pThat->mnDiscreteHeight = 0;
140 // use children as default context
141 aContent = getChildren();
143 // check if content needs to be clipped
144 const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
145 const basegfx::B2DRange aContentRange(getChildren().getB2DRange(rViewInformation));
147 if(!aUnitRange.isInside(aContentRange))
149 const Primitive2DReference xRef(
150 new MaskPrimitive2D(
151 basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aUnitRange)),
152 aContent));
154 aContent = Primitive2DContainer { xRef };
158 return aContent;
161 void PatternFillPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const
163 Primitive2DContainer aRetval;
165 if(getChildren().empty())
166 return;
168 if(!(!getReferenceRange().isEmpty() && getReferenceRange().getWidth() > 0.0 && getReferenceRange().getHeight() > 0.0))
169 return;
171 const basegfx::B2DRange aMaskRange(getMask().getB2DRange());
173 if(!(!aMaskRange.isEmpty() && aMaskRange.getWidth() > 0.0 && aMaskRange.getHeight() > 0.0))
174 return;
176 // create tiling matrices
177 std::vector< basegfx::B2DHomMatrix > aMatrices;
178 texture::GeoTexSvxTiled aTiling(getReferenceRange());
180 aTiling.appendTransformations(aMatrices);
182 // create content
183 const Primitive2DContainer aContent(createContent(rViewInformation));
185 // resize result
186 aRetval.resize(aMatrices.size());
188 // create one primitive for each matrix
189 for(size_t a(0); a < aMatrices.size(); a++)
191 aRetval[a] = new TransformPrimitive2D(
192 aMatrices[a],
193 aContent);
196 // transform result which is in unit coordinates to mask's object coordinates
198 const basegfx::B2DHomMatrix aMaskTransform(
199 basegfx::utils::createScaleTranslateB2DHomMatrix(
200 aMaskRange.getRange(),
201 aMaskRange.getMinimum()));
203 const Primitive2DReference xRef(
204 new TransformPrimitive2D(
205 aMaskTransform,
206 aRetval));
208 aRetval = Primitive2DContainer { xRef };
211 // embed result in mask
213 rContainer.push_back(
214 new MaskPrimitive2D(
215 getMask(),
216 aRetval));
220 PatternFillPrimitive2D::PatternFillPrimitive2D(
221 const basegfx::B2DPolyPolygon& rMask,
222 const Primitive2DContainer& rChildren,
223 const basegfx::B2DRange& rReferenceRange)
224 : BufferedDecompositionPrimitive2D(),
225 maMask(rMask),
226 maChildren(rChildren),
227 maReferenceRange(rReferenceRange),
228 mnDiscreteWidth(0),
229 mnDiscreteHeight(0)
233 bool PatternFillPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
235 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
237 const PatternFillPrimitive2D& rCompare = static_cast< const PatternFillPrimitive2D& >(rPrimitive);
239 return (getMask() == rCompare.getMask()
240 && getChildren() == rCompare.getChildren()
241 && getReferenceRange() == rCompare.getReferenceRange());
244 return false;
247 basegfx::B2DRange PatternFillPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /* rViewInformation */ ) const
249 return getMask().getB2DRange();
252 void PatternFillPrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
254 // The existing buffered decomposition uses a buffer in the remembered
255 // size or none if sizes are zero. Get new needed sizes which depend on
256 // the given ViewInformation
257 bool bResetBuffering = false;
258 sal_uInt32 nW(0);
259 sal_uInt32 nH(0);
260 calculateNeededDiscreteBufferSize(nW, nH, rViewInformation);
261 const bool bBufferingCurrentlyUsed(0 != mnDiscreteWidth && 0 != mnDiscreteHeight);
262 const bool bBufferingNextUsed(0 != nW && 0 != nH);
264 if(bBufferingNextUsed)
266 // buffering is now possible
267 if(bBufferingCurrentlyUsed)
269 if(nW > mnDiscreteWidth || nH > mnDiscreteHeight)
271 // Higher resolution is needed than used in the existing buffered
272 // decomposition - create new one
273 bResetBuffering = true;
275 else if(double(nW * nH) / double(mnDiscreteWidth * mnDiscreteHeight) <= 0.5)
277 // Size has shrunk for 50% or more - it's worth to refresh the buffering
278 // to spare some resources
279 bResetBuffering = true;
282 else
284 // currently no buffering used - reset evtl. unbuffered
285 // decomposition to start buffering
286 bResetBuffering = true;
289 else
291 // buffering is no longer possible
292 if(bBufferingCurrentlyUsed)
294 // reset decomposition to allow creation of unbuffered one
295 bResetBuffering = true;
299 if(bResetBuffering)
301 PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this);
302 pThat->mnDiscreteWidth = nW;
303 pThat->mnDiscreteHeight = nH;
304 pThat->setBuffered2DDecomposition(Primitive2DContainer());
307 // call parent
308 BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
311 sal_Int64 SAL_CALL PatternFillPrimitive2D::estimateUsage()
313 size_t nRet(0);
314 for (auto& it : getChildren())
316 uno::Reference<util::XAccounting> const xAcc(it, uno::UNO_QUERY);
317 if (xAcc.is())
319 nRet += xAcc->estimateUsage();
322 return nRet;
325 // provide unique ID
326 ImplPrimitive2DIDBlock(PatternFillPrimitive2D, PRIMITIVE2D_ID_PATTERNFILLPRIMITIVE2D)
328 } // end of namespace
330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */