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