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