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 { 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 59 void SAL_CALL UnoPolyPolygon::addPolyPolygon( 60 const geometry::RealPoint2D& position, 61 const uno::Reference< rendering::XPolyPolygon2D >& polyPolygon ) throw (lang::IllegalArgumentException,uno::RuntimeException) 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 141 sal_Int32 SAL_CALL UnoPolyPolygon::getNumberOfPolygons() throw (uno::RuntimeException) 142 { 143 osl::MutexGuard const guard( m_aMutex ); 144 return maPolyPoly.count(); 145 } 146 147 sal_Int32 SAL_CALL UnoPolyPolygon::getNumberOfPolygonPoints( 148 sal_Int32 polygon ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) 149 { 150 osl::MutexGuard const guard( m_aMutex ); 151 checkIndex( polygon ); 152 153 return maPolyPoly.getB2DPolygon(polygon).count(); 154 } 155 156 rendering::FillRule SAL_CALL UnoPolyPolygon::getFillRule() throw (uno::RuntimeException) 157 { 158 osl::MutexGuard const guard( m_aMutex ); 159 return meFillRule; 160 } 161 162 void SAL_CALL UnoPolyPolygon::setFillRule( 163 rendering::FillRule fillRule ) throw (uno::RuntimeException) 164 { 165 osl::MutexGuard const guard( m_aMutex ); 166 modifying(); 167 168 meFillRule = fillRule; 169 } 170 171 sal_Bool SAL_CALL UnoPolyPolygon::isClosed( 172 sal_Int32 index ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) 173 { 174 osl::MutexGuard const guard( m_aMutex ); 175 checkIndex( index ); 176 177 return maPolyPoly.getB2DPolygon(index).isClosed(); 178 } 179 180 void SAL_CALL UnoPolyPolygon::setClosed( 181 sal_Int32 index, 182 sal_Bool closedState ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) 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 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 ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) 210 { 211 osl::MutexGuard const guard( m_aMutex ); 212 213 return unotools::pointSequenceSequenceFromB2DPolyPolygon( 214 getSubsetPolyPolygon( nPolygonIndex, 215 nNumberOfPolygons, 216 nPointIndex, 217 nNumberOfPoints ) ); 218 } 219 220 void SAL_CALL UnoPolyPolygon::setPoints( 221 const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points, 222 sal_Int32 nPolygonIndex ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) 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 242 geometry::RealPoint2D SAL_CALL UnoPolyPolygon::getPoint( 243 sal_Int32 nPolygonIndex, 244 sal_Int32 nPointIndex ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) 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 257 void SAL_CALL UnoPolyPolygon::setPoint( 258 const geometry::RealPoint2D& point, 259 sal_Int32 nPolygonIndex, 260 sal_Int32 nPointIndex ) throw (lang::IndexOutOfBoundsException,uno::RuntimeException) 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 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 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 281 { 282 osl::MutexGuard const guard( m_aMutex ); 283 return unotools::bezierSequenceSequenceFromB2DPolyPolygon( 284 getSubsetPolyPolygon( nPolygonIndex, 285 nNumberOfPolygons, 286 nPointIndex, 287 nNumberOfPoints ) ); 288 } 289 290 void SAL_CALL UnoPolyPolygon::setBezierSegments( 291 const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points, 292 sal_Int32 nPolygonIndex ) throw (lang::IndexOutOfBoundsException, 293 uno::RuntimeException) 294 { 295 osl::MutexGuard const guard( m_aMutex ); 296 modifying(); 297 const B2DPolyPolygon& rNewPolyPoly( 298 unotools::polyPolygonFromBezier2DSequenceSequence( points ) ); 299 300 if( nPolygonIndex == -1 ) 301 { 302 maPolyPoly = rNewPolyPoly; 303 } 304 else 305 { 306 checkIndex( nPolygonIndex ); 307 308 maPolyPoly.insert( nPolygonIndex, rNewPolyPoly ); 309 } 310 } 311 312 geometry::RealBezierSegment2D SAL_CALL UnoPolyPolygon::getBezierSegment( sal_Int32 nPolygonIndex, 313 sal_Int32 nPointIndex ) throw (lang::IndexOutOfBoundsException, 314 uno::RuntimeException) 315 { 316 osl::MutexGuard const guard( m_aMutex ); 317 checkIndex( nPolygonIndex ); 318 319 const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); 320 const sal_uInt32 nPointCount(rPoly.count()); 321 322 if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(nPointCount) ) 323 throw lang::IndexOutOfBoundsException(); 324 325 const B2DPoint& rPt( rPoly.getB2DPoint( nPointIndex ) ); 326 const B2DPoint& rCtrl0( rPoly.getNextControlPoint(nPointIndex) ); 327 const B2DPoint& rCtrl1( rPoly.getPrevControlPoint((nPointIndex + 1) % nPointCount) ); 328 329 return geometry::RealBezierSegment2D( rPt.getX(), 330 rPt.getY(), 331 rCtrl0.getX(), 332 rCtrl0.getY(), 333 rCtrl1.getX(), 334 rCtrl1.getY() ); 335 } 336 337 void SAL_CALL UnoPolyPolygon::setBezierSegment( const geometry::RealBezierSegment2D& segment, 338 sal_Int32 nPolygonIndex, 339 sal_Int32 nPointIndex ) throw (lang::IndexOutOfBoundsException, 340 uno::RuntimeException) 341 { 342 osl::MutexGuard const guard( m_aMutex ); 343 checkIndex( nPolygonIndex ); 344 modifying(); 345 346 B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); 347 const sal_uInt32 nPointCount(aPoly.count()); 348 349 if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(nPointCount) ) 350 throw lang::IndexOutOfBoundsException(); 351 352 aPoly.setB2DPoint( nPointIndex, 353 B2DPoint( segment.Px, 354 segment.Py ) ); 355 aPoly.setNextControlPoint(nPointIndex, 356 B2DPoint(segment.C1x, segment.C1y)); 357 aPoly.setPrevControlPoint((nPointIndex + 1) % nPointCount, 358 B2DPoint(segment.C2x, segment.C2y)); 359 360 maPolyPoly.setB2DPolygon( nPolygonIndex, aPoly ); 361 } 362 363 B2DPolyPolygon UnoPolyPolygon::getSubsetPolyPolygon( 364 sal_Int32 nPolygonIndex, 365 sal_Int32 nNumberOfPolygons, 366 sal_Int32 nPointIndex, 367 sal_Int32 nNumberOfPoints ) const 368 { 369 osl::MutexGuard const guard( m_aMutex ); 370 checkIndex( nPolygonIndex ); 371 372 const sal_Int32 nPolyCount( maPolyPoly.count() ); 373 374 // check for "full polygon" case 375 if( !nPolygonIndex && 376 !nPointIndex && 377 nNumberOfPolygons == nPolyCount && 378 nNumberOfPoints == -1 ) 379 { 380 return maPolyPoly; 381 } 382 383 B2DPolyPolygon aSubsetPoly; 384 385 // create temporary polygon (as an extract from maPoly, 386 // which contains the requested subset) 387 for( sal_Int32 i=nPolygonIndex; i<nNumberOfPolygons; ++i ) 388 { 389 checkIndex(i); 390 391 const B2DPolygon& rCurrPoly( maPolyPoly.getB2DPolygon(i) ); 392 393 sal_Int32 nFirstPoint(0); 394 sal_Int32 nLastPoint(nPolyCount-1); 395 396 if( nPointIndex && i==nPolygonIndex ) 397 { 398 // very first polygon - respect nPointIndex, if 399 // not zero 400 401 // empty polygon - impossible to specify _any_ 402 // legal value except 0 here! 403 if( !nPolyCount && nPointIndex ) 404 throw lang::IndexOutOfBoundsException(); 405 406 nFirstPoint = nPointIndex; 407 } 408 409 if( i==nNumberOfPolygons-1 && nNumberOfPoints != -1 ) 410 { 411 // very last polygon - respect nNumberOfPoints 412 413 // empty polygon - impossible to specify _any_ 414 // legal value except -1 here! 415 if( !nPolyCount ) 416 throw lang::IndexOutOfBoundsException(); 417 418 nLastPoint = nFirstPoint+nNumberOfPoints; 419 } 420 421 if( !nPolyCount ) 422 { 423 // empty polygon - index checks already performed 424 // above, now simply append empty polygon 425 aSubsetPoly.append( rCurrPoly ); 426 } 427 else 428 { 429 if( nFirstPoint < 0 || nFirstPoint >= nPolyCount ) 430 throw lang::IndexOutOfBoundsException(); 431 432 if( nLastPoint < 0 || nLastPoint >= nPolyCount ) 433 throw lang::IndexOutOfBoundsException(); 434 435 B2DPolygon aTmp; 436 for( sal_Int32 j=nFirstPoint; j<nLastPoint; ++j ) 437 aTmp.append( rCurrPoly.getB2DPoint(j) ); 438 439 aSubsetPoly.append( aTmp ); 440 } 441 } 442 443 return aSubsetPoly; 444 } 445 446 B2DPolyPolygon UnoPolyPolygon::getPolyPolygonUnsafe() const 447 { 448 return maPolyPoly; 449 } 450 451 #define IMPLEMENTATION_NAME "gfx::internal::UnoPolyPolygon" 452 #define SERVICE_NAME "com.sun.star.rendering.PolyPolygon2D" 453 ::rtl::OUString SAL_CALL UnoPolyPolygon::getImplementationName() throw( uno::RuntimeException ) 454 { 455 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); 456 } 457 458 sal_Bool SAL_CALL UnoPolyPolygon::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException ) 459 { 460 return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); 461 } 462 463 uno::Sequence< ::rtl::OUString > SAL_CALL UnoPolyPolygon::getSupportedServiceNames() throw( uno::RuntimeException ) 464 { 465 uno::Sequence< ::rtl::OUString > aRet(1); 466 aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); 467 468 return aRet; 469 } 470 471 B2DPolyPolygon UnoPolyPolygon::getPolyPolygon() const 472 { 473 osl::MutexGuard const guard( m_aMutex ); 474 475 // detach result from us 476 B2DPolyPolygon aRet( maPolyPoly ); 477 aRet.makeUnique(); 478 return aRet; 479 } 480 481 } 482 } 483