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