xref: /trunk/main/basegfx/source/tools/unopolypolygon.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basegfx.hxx"
26 
27 #include <com/sun/star/geometry/AffineMatrix2D.hpp>
28 #include <com/sun/star/rendering/RenderState.hpp>
29 #include <com/sun/star/rendering/ViewState.hpp>
30 #include <com/sun/star/rendering/XCanvas.hpp>
31 #include <com/sun/star/rendering/CompositeOperation.hpp>
32 
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <basegfx/range/b2drange.hxx>
35 #include <basegfx/range/b2drectangle.hxx>
36 #include <basegfx/point/b2dpoint.hxx>
37 #include <basegfx/tools/canvastools.hxx>
38 #include <basegfx/polygon/b2dpolygon.hxx>
39 #include <basegfx/polygon/b2dpolypolygontools.hxx>
40 #include <basegfx/tools/unopolypolygon.hxx>
41 #include <basegfx/matrix/b2dhommatrixtools.hxx>
42 
43 
44 using namespace ::com::sun::star;
45 
46 namespace basegfx
47 {
48 namespace unotools
49 {
UnoPolyPolygon(const B2DPolyPolygon & rPolyPoly)50     UnoPolyPolygon::UnoPolyPolygon( const B2DPolyPolygon& rPolyPoly ) :
51         UnoPolyPolygonBase( m_aMutex ),
52         maPolyPoly( rPolyPoly ),
53         meFillRule( rendering::FillRule_EVEN_ODD )
54     {
55         // or else races will haunt us.
56         maPolyPoly.makeUnique();
57     }
58 
addPolyPolygon(const geometry::RealPoint2D & position,const uno::Reference<rendering::XPolyPolygon2D> & polyPolygon)59     void SAL_CALL UnoPolyPolygon::addPolyPolygon(
60         const geometry::RealPoint2D&                        position,
61         const uno::Reference< rendering::XPolyPolygon2D >&  polyPolygon )
62     {
63         osl::MutexGuard const guard( m_aMutex );
64         modifying();
65 
66         // TODO(F1): Correctly fulfill the UNO API
67         // specification. This will probably result in a vector of
68         // poly-polygons to be stored in this object.
69 
70         const sal_Int32 nPolys( polyPolygon->getNumberOfPolygons() );
71 
72         if( !polyPolygon.is() || !nPolys )
73         {
74             // invalid or empty polygon - nothing to do.
75             return;
76         }
77 
78         B2DPolyPolygon        aSrcPoly;
79         const UnoPolyPolygon* pSrc( dynamic_cast< UnoPolyPolygon* >(polyPolygon.get()) );
80 
81         // try to extract polygon data from interface. First,
82         // check whether it's the same implementation object,
83         // which we can tunnel then.
84         if( pSrc )
85         {
86             aSrcPoly = pSrc->getPolyPolygon();
87         }
88         else
89         {
90             // not a known implementation object - try data source
91             // interfaces
92             uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly(
93                 polyPolygon,
94                 uno::UNO_QUERY );
95 
96             if( xBezierPoly.is() )
97             {
98                 aSrcPoly = unotools::polyPolygonFromBezier2DSequenceSequence(
99                     xBezierPoly->getBezierSegments( 0,
100                                                     nPolys,
101                                                     0,
102                                                     -1 ) );
103             }
104             else
105             {
106                 uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly(
107                     polyPolygon,
108                     uno::UNO_QUERY );
109 
110                 // no implementation class and no data provider
111                 // found - contract violation.
112                 if( !xLinePoly.is() )
113                     throw lang::IllegalArgumentException(
114                         ::rtl::OUString(
115                             RTL_CONSTASCII_USTRINGPARAM(
116                                 "UnoPolyPolygon::addPolyPolygon(): Invalid input "
117                                 "poly-polygon, cannot retrieve vertex data")),
118                         static_cast<cppu::OWeakObject*>(this), 1);
119 
120                 aSrcPoly = unotools::polyPolygonFromPoint2DSequenceSequence(
121                     xLinePoly->getPoints( 0,
122                                           nPolys,
123                                           0,
124                                           -1 ) );
125             }
126         }
127 
128         const B2DRange  aBounds( tools::getRange( aSrcPoly ) );
129         const B2DVector     aOffset( unotools::b2DPointFromRealPoint2D( position ) -
130                                              aBounds.getMinimum() );
131 
132         if( !aOffset.equalZero() )
133         {
134             const B2DHomMatrix aTranslate(tools::createTranslateB2DHomMatrix(aOffset));
135             aSrcPoly.transform( aTranslate );
136         }
137 
138         maPolyPoly.append( aSrcPoly );
139     }
140 
getNumberOfPolygons()141     sal_Int32 SAL_CALL UnoPolyPolygon::getNumberOfPolygons()
142     {
143         osl::MutexGuard const guard( m_aMutex );
144         return maPolyPoly.count();
145     }
146 
getNumberOfPolygonPoints(sal_Int32 polygon)147     sal_Int32 SAL_CALL UnoPolyPolygon::getNumberOfPolygonPoints(
148         sal_Int32 polygon )
149     {
150         osl::MutexGuard const guard( m_aMutex );
151         checkIndex( polygon );
152 
153         return maPolyPoly.getB2DPolygon(polygon).count();
154     }
155 
getFillRule()156     rendering::FillRule SAL_CALL UnoPolyPolygon::getFillRule()
157     {
158         osl::MutexGuard const guard( m_aMutex );
159         return meFillRule;
160     }
161 
setFillRule(rendering::FillRule fillRule)162     void SAL_CALL UnoPolyPolygon::setFillRule(
163         rendering::FillRule fillRule )
164     {
165         osl::MutexGuard const guard( m_aMutex );
166         modifying();
167 
168         meFillRule = fillRule;
169     }
170 
isClosed(sal_Int32 index)171     sal_Bool SAL_CALL UnoPolyPolygon::isClosed(
172         sal_Int32 index )
173     {
174         osl::MutexGuard const guard( m_aMutex );
175         checkIndex( index );
176 
177         return maPolyPoly.getB2DPolygon(index).isClosed();
178     }
179 
setClosed(sal_Int32 index,sal_Bool closedState)180     void SAL_CALL UnoPolyPolygon::setClosed(
181         sal_Int32 index,
182         sal_Bool closedState )
183     {
184         osl::MutexGuard const guard( m_aMutex );
185         modifying();
186 
187         if( index == -1L )
188         {
189             // set all
190             maPolyPoly.setClosed( closedState );
191         }
192         else
193         {
194             checkIndex( index );
195 
196             // fetch referenced polygon, change state
197             B2DPolygon aTmp( maPolyPoly.getB2DPolygon(index) );
198             aTmp.setClosed( closedState );
199 
200             // set back to container
201             maPolyPoly.setB2DPolygon( index, aTmp );
202         }
203     }
204 
getPoints(sal_Int32 nPolygonIndex,sal_Int32 nNumberOfPolygons,sal_Int32 nPointIndex,sal_Int32 nNumberOfPoints)205     uno::Sequence< uno::Sequence< geometry::RealPoint2D > > SAL_CALL UnoPolyPolygon::getPoints(
206         sal_Int32 nPolygonIndex,
207         sal_Int32 nNumberOfPolygons,
208         sal_Int32 nPointIndex,
209         sal_Int32 nNumberOfPoints )
210     {
211         osl::MutexGuard const guard( m_aMutex );
212 
213         return unotools::pointSequenceSequenceFromB2DPolyPolygon(
214             getSubsetPolyPolygon( nPolygonIndex,
215                                   nNumberOfPolygons,
216                                   nPointIndex,
217                                   nNumberOfPoints ) );
218     }
219 
setPoints(const uno::Sequence<uno::Sequence<geometry::RealPoint2D>> & points,sal_Int32 nPolygonIndex)220     void SAL_CALL UnoPolyPolygon::setPoints(
221         const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points,
222         sal_Int32 nPolygonIndex )
223     {
224         osl::MutexGuard const guard( m_aMutex );
225         modifying();
226 
227         const B2DPolyPolygon& rNewPolyPoly(
228             unotools::polyPolygonFromPoint2DSequenceSequence( points ) );
229 
230         if( nPolygonIndex == -1 )
231         {
232             maPolyPoly = rNewPolyPoly;
233         }
234         else
235         {
236             checkIndex( nPolygonIndex );
237 
238             maPolyPoly.insert( nPolygonIndex, rNewPolyPoly );
239         }
240     }
241 
getPoint(sal_Int32 nPolygonIndex,sal_Int32 nPointIndex)242     geometry::RealPoint2D SAL_CALL UnoPolyPolygon::getPoint(
243         sal_Int32 nPolygonIndex,
244         sal_Int32 nPointIndex )
245     {
246         osl::MutexGuard const guard( m_aMutex );
247         checkIndex( nPolygonIndex );
248 
249         const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) );
250 
251         if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(rPoly.count()) )
252             throw lang::IndexOutOfBoundsException();
253 
254         return unotools::point2DFromB2DPoint( rPoly.getB2DPoint( nPointIndex ) );
255     }
256 
setPoint(const geometry::RealPoint2D & point,sal_Int32 nPolygonIndex,sal_Int32 nPointIndex)257     void SAL_CALL UnoPolyPolygon::setPoint(
258         const geometry::RealPoint2D& point,
259         sal_Int32 nPolygonIndex,
260         sal_Int32 nPointIndex )
261     {
262         osl::MutexGuard const guard( m_aMutex );
263         checkIndex( nPolygonIndex );
264         modifying();
265 
266         B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) );
267 
268         if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(aPoly.count()) )
269             throw lang::IndexOutOfBoundsException();
270 
271         aPoly.setB2DPoint( nPointIndex,
272                            unotools::b2DPointFromRealPoint2D( point ) );
273         maPolyPoly.setB2DPolygon( nPolygonIndex, aPoly );
274     }
275 
getBezierSegments(sal_Int32 nPolygonIndex,sal_Int32 nNumberOfPolygons,sal_Int32 nPointIndex,sal_Int32 nNumberOfPoints)276     uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > SAL_CALL UnoPolyPolygon::getBezierSegments(
277         sal_Int32 nPolygonIndex,
278         sal_Int32 nNumberOfPolygons,
279         sal_Int32 nPointIndex,
280         sal_Int32 nNumberOfPoints )
281     {
282         osl::MutexGuard const guard( m_aMutex );
283         return unotools::bezierSequenceSequenceFromB2DPolyPolygon(
284             getSubsetPolyPolygon( nPolygonIndex,
285                                   nNumberOfPolygons,
286                                   nPointIndex,
287                                   nNumberOfPoints ) );
288     }
289 
setBezierSegments(const uno::Sequence<uno::Sequence<geometry::RealBezierSegment2D>> & points,sal_Int32 nPolygonIndex)290     void SAL_CALL UnoPolyPolygon::setBezierSegments(
291         const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >&  points,
292         sal_Int32                                                               nPolygonIndex )
293     {
294         osl::MutexGuard const guard( m_aMutex );
295         modifying();
296         const B2DPolyPolygon& rNewPolyPoly(
297             unotools::polyPolygonFromBezier2DSequenceSequence( points ) );
298 
299         if( nPolygonIndex == -1 )
300         {
301             maPolyPoly = rNewPolyPoly;
302         }
303         else
304         {
305             checkIndex( nPolygonIndex );
306 
307             maPolyPoly.insert( nPolygonIndex, rNewPolyPoly );
308         }
309     }
310 
getBezierSegment(sal_Int32 nPolygonIndex,sal_Int32 nPointIndex)311     geometry::RealBezierSegment2D SAL_CALL UnoPolyPolygon::getBezierSegment( sal_Int32 nPolygonIndex,
312                                                                              sal_Int32 nPointIndex )
313     {
314         osl::MutexGuard const guard( m_aMutex );
315         checkIndex( nPolygonIndex );
316 
317         const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) );
318         const sal_uInt32  nPointCount(rPoly.count());
319 
320         if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(nPointCount) )
321             throw lang::IndexOutOfBoundsException();
322 
323         const B2DPoint& rPt( rPoly.getB2DPoint( nPointIndex ) );
324         const B2DPoint& rCtrl0( rPoly.getNextControlPoint(nPointIndex) );
325         const B2DPoint& rCtrl1( rPoly.getPrevControlPoint((nPointIndex + 1) % nPointCount) );
326 
327         return geometry::RealBezierSegment2D( rPt.getX(),
328                                               rPt.getY(),
329                                               rCtrl0.getX(),
330                                               rCtrl0.getY(),
331                                               rCtrl1.getX(),
332                                               rCtrl1.getY() );
333     }
334 
setBezierSegment(const geometry::RealBezierSegment2D & segment,sal_Int32 nPolygonIndex,sal_Int32 nPointIndex)335     void SAL_CALL UnoPolyPolygon::setBezierSegment( const geometry::RealBezierSegment2D& segment,
336                                                          sal_Int32                       nPolygonIndex,
337                                                          sal_Int32                       nPointIndex )
338     {
339         osl::MutexGuard const guard( m_aMutex );
340         checkIndex( nPolygonIndex );
341         modifying();
342 
343         B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) );
344         const sal_uInt32 nPointCount(aPoly.count());
345 
346         if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(nPointCount) )
347             throw lang::IndexOutOfBoundsException();
348 
349         aPoly.setB2DPoint( nPointIndex,
350                            B2DPoint( segment.Px,
351                                      segment.Py ) );
352         aPoly.setNextControlPoint(nPointIndex,
353                                   B2DPoint(segment.C1x, segment.C1y));
354         aPoly.setPrevControlPoint((nPointIndex + 1) % nPointCount,
355                                   B2DPoint(segment.C2x, segment.C2y));
356 
357         maPolyPoly.setB2DPolygon( nPolygonIndex, aPoly );
358     }
359 
getSubsetPolyPolygon(sal_Int32 nPolygonIndex,sal_Int32 nNumberOfPolygons,sal_Int32 nPointIndex,sal_Int32 nNumberOfPoints) const360     B2DPolyPolygon UnoPolyPolygon::getSubsetPolyPolygon(
361         sal_Int32 nPolygonIndex,
362         sal_Int32 nNumberOfPolygons,
363         sal_Int32 nPointIndex,
364         sal_Int32 nNumberOfPoints ) const
365     {
366         osl::MutexGuard const guard( m_aMutex );
367         checkIndex( nPolygonIndex );
368 
369         const sal_Int32 nPolyCount( maPolyPoly.count() );
370 
371         // check for "full polygon" case
372         if( !nPolygonIndex &&
373             !nPointIndex &&
374             nNumberOfPolygons == nPolyCount &&
375             nNumberOfPoints == -1 )
376         {
377             return maPolyPoly;
378         }
379 
380         B2DPolyPolygon aSubsetPoly;
381 
382         // create temporary polygon (as an extract from maPoly,
383         // which contains the requested subset)
384         for( sal_Int32 i=nPolygonIndex; i<nNumberOfPolygons; ++i )
385         {
386             checkIndex(i);
387 
388             const B2DPolygon& rCurrPoly( maPolyPoly.getB2DPolygon(i) );
389 
390             sal_Int32 nFirstPoint(0);
391             sal_Int32 nLastPoint(nPolyCount-1);
392 
393             if( nPointIndex && i==nPolygonIndex )
394             {
395                 // very first polygon - respect nPointIndex, if
396                 // not zero
397 
398                 // empty polygon - impossible to specify _any_
399                 // legal value except 0 here!
400                 if( !nPolyCount && nPointIndex )
401                     throw lang::IndexOutOfBoundsException();
402 
403                 nFirstPoint = nPointIndex;
404             }
405 
406             if( i==nNumberOfPolygons-1 && nNumberOfPoints != -1 )
407             {
408                 // very last polygon - respect nNumberOfPoints
409 
410                 // empty polygon - impossible to specify _any_
411                 // legal value except -1 here!
412                 if( !nPolyCount )
413                     throw lang::IndexOutOfBoundsException();
414 
415                 nLastPoint = nFirstPoint+nNumberOfPoints;
416             }
417 
418             if( !nPolyCount )
419             {
420                 // empty polygon - index checks already performed
421                 // above, now simply append empty polygon
422                 aSubsetPoly.append( rCurrPoly );
423             }
424             else
425             {
426                 if( nFirstPoint < 0 || nFirstPoint >= nPolyCount )
427                     throw lang::IndexOutOfBoundsException();
428 
429                 if( nLastPoint < 0 || nLastPoint >= nPolyCount )
430                     throw lang::IndexOutOfBoundsException();
431 
432                 B2DPolygon aTmp;
433                 for( sal_Int32 j=nFirstPoint; j<nLastPoint; ++j )
434                     aTmp.append( rCurrPoly.getB2DPoint(j) );
435 
436                 aSubsetPoly.append( aTmp );
437             }
438         }
439 
440         return aSubsetPoly;
441     }
442 
getPolyPolygonUnsafe() const443     B2DPolyPolygon UnoPolyPolygon::getPolyPolygonUnsafe() const
444     {
445         return maPolyPoly;
446     }
447 
448 #define IMPLEMENTATION_NAME "gfx::internal::UnoPolyPolygon"
449 #define SERVICE_NAME "com.sun.star.rendering.PolyPolygon2D"
getImplementationName()450     ::rtl::OUString SAL_CALL UnoPolyPolygon::getImplementationName()
451     {
452         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
453     }
454 
supportsService(const::rtl::OUString & ServiceName)455     sal_Bool SAL_CALL UnoPolyPolygon::supportsService( const ::rtl::OUString& ServiceName )
456     {
457         return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
458     }
459 
getSupportedServiceNames()460     uno::Sequence< ::rtl::OUString > SAL_CALL UnoPolyPolygon::getSupportedServiceNames()
461     {
462         uno::Sequence< ::rtl::OUString > aRet(1);
463         aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
464 
465         return aRet;
466     }
467 
getPolyPolygon() const468     B2DPolyPolygon UnoPolyPolygon::getPolyPolygon() const
469     {
470         osl::MutexGuard const guard( m_aMutex );
471 
472         // detach result from us
473         B2DPolyPolygon aRet( maPolyPoly );
474         aRet.makeUnique();
475         return aRet;
476     }
477 
478 }
479 }
480