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