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 #ifndef INCLUDED_CANVAS_CANVASTOOLS_HXX 25 #define INCLUDED_CANVAS_CANVASTOOLS_HXX 26 27 #include <rtl/math.hxx> 28 #include <com/sun/star/uno/Reference.hxx> 29 #include <com/sun/star/uno/Sequence.hxx> 30 #include <com/sun/star/uno/RuntimeException.hpp> 31 #include <com/sun/star/lang/IllegalArgumentException.hpp> 32 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 33 #include <osl/diagnose.h> 34 #include <rtl/ustring.hxx> 35 36 #include <string.h> // for strcmp 37 #include <vector> 38 #include <limits> 39 #include <algorithm> 40 41 42 namespace basegfx 43 { 44 class B2DHomMatrix; 45 class B2DRange; 46 class B2IRange; 47 class B2IPoint; 48 class B2DPolyPolygon; 49 } 50 51 namespace com { namespace sun { namespace star { namespace geometry 52 { 53 struct RealSize2D; 54 struct IntegerSize2D; 55 struct AffineMatrix2D; 56 struct Matrix2D; 57 } } } } 58 59 namespace com { namespace sun { namespace star { namespace rendering 60 { 61 struct RenderState; 62 struct ViewState; 63 struct IntegerBitmapLayout; 64 class XCanvas; 65 struct Texture; 66 class XIntegerBitmapColorSpace; 67 class XPolyPolygon2D; 68 69 bool operator==( const RenderState& rLHS, 70 const RenderState& rRHS ); 71 72 bool operator==( const ViewState& rLHS, 73 const ViewState& rRHS ); 74 } } } } 75 76 namespace com { namespace sun { namespace star { namespace awt 77 { 78 struct Rectangle; 79 class XWindow2; 80 } } } } 81 82 class Color; 83 84 namespace canvas 85 { 86 namespace tools 87 { 88 /** Compute the next highest power of 2 of a 32-bit value 89 90 Code devised by Sean Anderson, in good ole HAKMEM 91 tradition. 92 93 @return 1 << (lg(x - 1) + 1) 94 */ nextPow2(sal_uInt32 x)95 inline sal_uInt32 nextPow2( sal_uInt32 x ) 96 { 97 --x; 98 x |= x >> 1; 99 x |= x >> 2; 100 x |= x >> 4; 101 x |= x >> 8; 102 x |= x >> 16; 103 104 return ++x; 105 } 106 107 /** 108 * 109 * Count the number of 1-bits of an n-bit value 110 * 111 */ 112 113 // mickey's math tricks... pow2(unsigned int c)114 inline unsigned int pow2( unsigned int c ) { return 0x1 << c; } mask(unsigned int c)115 inline unsigned int mask( unsigned int c ) { return ((unsigned int)(-1)) / (pow2(pow2(c)) + 1); } count(unsigned int x,unsigned int c)116 inline unsigned int count( unsigned int x, unsigned int c ) { return ((x) & mask(c)) + (((x) >> (pow2(c))) & mask(c)); } 117 template<typename T> bitcount(T c)118 inline unsigned int bitcount( T c ) { 119 unsigned int nByteIndex = 0; 120 unsigned int nNumBytes = sizeof(T)<<2; 121 do { 122 c=count(c,nByteIndex++); 123 nNumBytes >>= 1; 124 } while(nNumBytes); 125 return c; 126 } bitcount32(sal_uInt32 c)127 inline sal_uInt32 bitcount32( sal_uInt32 c ) { 128 c=count(c,0); 129 c=count(c,1); 130 c=count(c,2); 131 c=count(c,3); 132 c=count(c,4); 133 return c; 134 } 135 136 /** Round given floating point value down to next integer 137 */ roundDown(const double & rVal)138 inline sal_Int32 roundDown( const double& rVal ) 139 { 140 return static_cast< sal_Int32 >( floor( rVal ) ); 141 } 142 143 /** Round given floating point value up to next integer 144 */ roundUp(const double & rVal)145 inline sal_Int32 roundUp( const double& rVal ) 146 { 147 return static_cast< sal_Int32 >( ceil( rVal ) ); 148 } 149 150 /** Create a RealSize2D with both coordinate values set to +infinity 151 */ 152 ::com::sun::star::geometry::RealSize2D createInfiniteSize2D(); 153 154 155 // View- and RenderState utilities 156 // =================================================================== 157 158 ::com::sun::star::rendering::RenderState& 159 initRenderState( ::com::sun::star::rendering::RenderState& renderState ); 160 161 ::com::sun::star::rendering::ViewState& 162 initViewState( ::com::sun::star::rendering::ViewState& viewState ); 163 164 ::basegfx::B2DHomMatrix& 165 getViewStateTransform( ::basegfx::B2DHomMatrix& transform, 166 const ::com::sun::star::rendering::ViewState& viewState ); 167 168 ::com::sun::star::rendering::ViewState& 169 setViewStateTransform( ::com::sun::star::rendering::ViewState& viewState, 170 const ::basegfx::B2DHomMatrix& transform ); 171 172 ::basegfx::B2DHomMatrix& 173 getRenderStateTransform( ::basegfx::B2DHomMatrix& transform, 174 const ::com::sun::star::rendering::RenderState& renderState ); 175 176 ::com::sun::star::rendering::RenderState& 177 setRenderStateTransform( ::com::sun::star::rendering::RenderState& renderState, 178 const ::basegfx::B2DHomMatrix& transform ); 179 180 ::com::sun::star::rendering::ViewState& 181 appendToViewState( ::com::sun::star::rendering::ViewState& viewState, 182 const ::basegfx::B2DHomMatrix& transform ); 183 184 ::com::sun::star::rendering::RenderState& 185 appendToRenderState( ::com::sun::star::rendering::RenderState& renderState, 186 const ::basegfx::B2DHomMatrix& transform ); 187 188 ::com::sun::star::rendering::ViewState& 189 prependToViewState( ::com::sun::star::rendering::ViewState& viewState, 190 const ::basegfx::B2DHomMatrix& transform ); 191 192 ::com::sun::star::rendering::RenderState& 193 prependToRenderState( ::com::sun::star::rendering::RenderState& renderState, 194 const ::basegfx::B2DHomMatrix& transform ); 195 196 ::basegfx::B2DHomMatrix& 197 mergeViewAndRenderTransform( ::basegfx::B2DHomMatrix& transform, 198 const ::com::sun::star::rendering::ViewState& viewState, 199 const ::com::sun::star::rendering::RenderState& renderState ); 200 201 ::com::sun::star::rendering::ViewState& 202 mergeViewAndRenderState( ::com::sun::star::rendering::ViewState& resultViewState, 203 const ::com::sun::star::rendering::ViewState& viewState, 204 const ::com::sun::star::rendering::RenderState& renderState, 205 const ::com::sun::star::uno::Reference< 206 ::com::sun::star::rendering::XCanvas >& xCanvas ); 207 208 209 // Matrix utilities 210 // =================================================================== 211 212 ::com::sun::star::geometry::AffineMatrix2D& 213 setIdentityAffineMatrix2D( ::com::sun::star::geometry::AffineMatrix2D& matrix ); 214 215 ::com::sun::star::geometry::Matrix2D& 216 setIdentityMatrix2D( ::com::sun::star::geometry::Matrix2D& matrix ); 217 218 219 // Special utilities 220 // =================================================================== 221 222 /** Calc the bounding rectangle of a transformed rectangle. 223 224 The method applies the given transformation to the 225 specified input rectangle, and returns the bounding box of 226 the resulting output area. 227 228 @param o_Rect 229 Output rectangle 230 231 @param i_Rect 232 Input rectangle 233 234 @param i_Transformation 235 Transformation to apply to the input rectangle 236 237 @see calcRectToRectTransform() 238 239 @return a reference to the resulting rectangle 240 */ 241 ::basegfx::B2DRange& calcTransformedRectBounds( ::basegfx::B2DRange& o_Rect, 242 const ::basegfx::B2DRange& i_Rect, 243 const ::basegfx::B2DHomMatrix& i_Transformation ); 244 245 /** Calc a transform that maps one rectangle on top of 246 another. 247 248 The method is a kissing cousin to 249 calcTransformedRectBounds(). It can be used to modify the 250 given transformation matrix, such that it transforms the 251 given input rectangle to the given output rectangle, 252 changing only translation and scale (if necessary). Thus, 253 if you've calculated an output rectangle via 254 calcTransformedRectBounds(), you can move and scale that 255 rectangle as you like, and have this method calculate the 256 required total transformation for it. 257 258 @param o_transform 259 Output parameter, to receive the resulting transformation 260 matrix. 261 262 @param i_destRect 263 Input parameter, specifies the requested destination 264 rectangle. The resulting transformation will exactly map 265 the source rectangle to the destination rectangle. 266 267 @param i_srcRect 268 Input parameter, specifies the original source 269 rectangle. The resulting transformation will exactly map 270 the source rectangle to the destination rectangle. 271 272 @param i_transformation 273 The original transformation matrix. This is changed with 274 translations and scalings (if necessary), to exactly map 275 the source rectangle to the destination rectangle. 276 277 @return a reference to the resulting transformation matrix 278 279 @see calcTransformedRectBounds() 280 */ 281 ::basegfx::B2DHomMatrix& calcRectToRectTransform( ::basegfx::B2DHomMatrix& o_transform, 282 const ::basegfx::B2DRange& i_destRect, 283 const ::basegfx::B2DRange& i_srcRect, 284 const ::basegfx::B2DHomMatrix& i_transformation ); 285 286 /** Calc a transform that maps the upper, left corner of a 287 rectangle to the origin. 288 289 The method is a specialized version of 290 calcRectToRectTransform(), mapping the input rectangle's 291 the upper, left corner to the origin, and leaving the size 292 untouched. 293 294 @param o_transform 295 Output parameter, to receive the resulting transformation 296 matrix. 297 298 @param i_srcRect 299 Input parameter, specifies the original source 300 rectangle. The resulting transformation will exactly map 301 the source rectangle's upper, left corner to the origin. 302 303 @param i_transformation 304 The original transformation matrix. This is changed with 305 translations (if necessary), to exactly map the source 306 rectangle to the origin. 307 308 @return a reference to the resulting transformation matrix 309 310 @see calcRectToRectTransform() 311 @see calcTransformedRectBounds() 312 */ 313 ::basegfx::B2DHomMatrix& calcRectToOriginTransform( ::basegfx::B2DHomMatrix& o_transform, 314 const ::basegfx::B2DRange& i_srcRect, 315 const ::basegfx::B2DHomMatrix& i_transformation ); 316 317 /** Check whether a given rectangle is within another 318 transformed rectangle. 319 320 This method checks for polygonal containedness, i.e. the 321 transformed rectangle is not represented as an axis-alignd 322 rectangle anymore (like calcTransformedRectBounds()), but 323 polygonal. Thus, the insideness test is based on tight 324 bounds. 325 326 @param rContainedRect 327 This rectangle is checked, whether it is fully within the 328 transformed rTransformRect. 329 330 @param rTransformRect 331 This rectangle is transformed, and then checked whether it 332 fully contains rContainedRect. 333 334 @param rTransformation 335 This transformation is applied to rTransformRect 336 */ 337 bool isInside( const ::basegfx::B2DRange& rContainedRect, 338 const ::basegfx::B2DRange& rTransformRect, 339 const ::basegfx::B2DHomMatrix& rTransformation ); 340 341 /** Clip a scroll to the given bound rect 342 343 @param io_rSourceArea 344 Source area to scroll. The resulting clipped source area 345 is returned therein. 346 347 @param io_rDestPoint 348 Destination point of the scroll (upper, left corner of 349 rSourceArea after the scroll). The new, resulting 350 destination point is returned therein.q 351 352 @param o_ClippedAreas 353 Vector of rectangles in the <em>destination</em> area 354 coordinate system, which are clipped away from the source 355 area, and thus need extra updates (i.e. they are not 356 correctly copy from the scroll operation, since there was 357 no information about them in the source). 358 359 @param rBounds 360 Bounds to clip against. 361 362 @return false, if the resulting scroll area is empty 363 */ 364 bool clipScrollArea( ::basegfx::B2IRange& io_rSourceArea, 365 ::basegfx::B2IPoint& io_rDestPoint, 366 ::std::vector< ::basegfx::B2IRange >& o_ClippedAreas, 367 const ::basegfx::B2IRange& rBounds ); 368 369 /** Clip a blit between two differently surfaces. 370 371 This method clips source and dest rect for a clip between 372 two differently clipped surfaces, such that the resulting 373 blit rects are fully within both clip areas. 374 375 @param io_rSourceArea 376 Source area of the blit. Returned therein is the computed 377 clipped source area. 378 379 @param io_rDestPoint 380 Dest area of the blit. Returned therein is the computed 381 clipped dest area. 382 383 @param rSourceBounds 384 Clip bounds of the source surface 385 386 @param rDestBounds 387 Clip bounds of the dest surface 388 389 @return false, if the resulting blit is empty, i.e. fully 390 clipped away. 391 */ 392 bool clipBlit( ::basegfx::B2IRange& io_rSourceArea, 393 ::basegfx::B2IPoint& io_rDestPoint, 394 const ::basegfx::B2IRange& rSourceBounds, 395 const ::basegfx::B2IRange& rDestBounds ); 396 397 /** Return range of integer pixel, which will cover the sprite 398 given by the floating point range. 399 400 This method assumes that sprite sizes are always integer, 401 and that the sprite position (top, left edge of the 402 sprite) is rounded to the nearest integer before 403 rendering. 404 405 @param rRange 406 Input range. Values must be within the representable 407 bounds of sal_Int32 408 409 @return the integer range, which is covered by the sprite 410 given by rRange. 411 */ 412 ::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange ); 413 414 /** Retrieve various internal properties of the actual canvas implementation. 415 416 This method retrieves a bunch of internal, implementation- 417 and platform-dependent values from the canvas 418 implementation. Among them are for example operating 419 system window handles. The actual layout and content of 420 the returned sequence is dependent on the component 421 implementation, undocumented and subject to change. 422 423 @param i_rxCanvas 424 Input parameter, the canvas representation for which the device information 425 is to be retrieveds 426 427 @param o_rxParams 428 Output parameter, the sequence of Anys that hold the device parameters. Layout is as described above 429 430 @return A reference to the resulting sequence of parameters 431 */ 432 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& getDeviceInfo( 433 const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas >& i_rxCanvas, 434 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& o_rxParams ); 435 436 /** Return a color space for a default RGBA integer format 437 438 Use this method for dead-simple bitmap implementations, 439 that map all their formats to 8888 RGBA color. 440 */ 441 ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XIntegerBitmapColorSpace> getStdColorSpace(); 442 443 /** Return a memory layout for a default RGBA integer format 444 445 Use this method for dead-simple bitmap implementations, 446 that map all their formats to 8888 RGBA color. 447 */ 448 ::com::sun::star::rendering::IntegerBitmapLayout getStdMemoryLayout( 449 const ::com::sun::star::geometry::IntegerSize2D& rBitmapSize ); 450 451 /// Convert standard 8888 RGBA color to vcl color 452 ::Color stdIntSequenceToColor( const ::com::sun::star::uno::Sequence<sal_Int8>& rColor ); 453 454 /// Convert standard 8888 RGBA color to vcl color 455 ::com::sun::star::uno::Sequence<sal_Int8> colorToStdIntSequence( const ::Color& rColor ); 456 457 // Modeled closely after boost::numeric_cast, only that we 458 // issue some trace output here and throw a RuntimeException 459 460 /** Cast numeric value into another (numeric) data type 461 462 Apart from converting the numeric value, this template 463 also checks if any overflow, underflow, or sign 464 information is lost (if yes, it throws an 465 uno::RuntimeException. 466 */ numeric_cast(Source arg)467 template< typename Target, typename Source > inline Target numeric_cast( Source arg ) 468 { 469 // typedefs abbreviating respective trait classes 470 typedef ::std::numeric_limits< Source > SourceLimits; 471 typedef ::std::numeric_limits< Target > TargetLimits; 472 473 if( ( arg<0 && !TargetLimits::is_signed) || // loosing the sign here 474 ( SourceLimits::is_signed && arg<TargetLimits::min()) || // underflow will happen 475 ( arg>TargetLimits::max() ) ) // overflow will happen 476 { 477 #if defined(VERBOSE) && defined(DBG_UTIL) 478 OSL_TRACE("numeric_cast detected data loss"); 479 #endif 480 throw ::com::sun::star::uno::RuntimeException( 481 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "numeric_cast detected data loss" )), 482 NULL ); 483 } 484 485 return static_cast<Target>(arg); 486 } 487 488 ::com::sun::star::awt::Rectangle getAbsoluteWindowRect( 489 const ::com::sun::star::awt::Rectangle& rRect, 490 const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow2 >& xWin ); 491 492 /** Retrieve for small bound marks around each corner of the given rectangle 493 */ 494 ::basegfx::B2DPolyPolygon getBoundMarksPolyPolygon( const ::basegfx::B2DRange& rRange ); 495 496 /** Calculate number of gradient "strips" to generate (takes 497 into account device resolution) 498 499 @param nColorSteps 500 Maximal integer difference between all color stops, needed 501 for smooth gradient color differences 502 */ 503 int calcGradientStepCount( ::basegfx::B2DHomMatrix& rTotalTransform, 504 const ::com::sun::star::rendering::ViewState& viewState, 505 const ::com::sun::star::rendering::RenderState& renderState, 506 const ::com::sun::star::rendering::Texture& texture, 507 int nColorSteps ); 508 509 /** A very simplistic map for ASCII strings and arbitrary value 510 types. 511 512 This class internally references a constant, static array of 513 sorted MapEntries, and performs a binary search to look up 514 values for a given query string. Note that this map is static, 515 i.e. not meant to be extented at runtime. 516 517 @tpl ValueType 518 The value type this map should store, associated with an ASCII 519 string. 520 */ 521 template< typename ValueType > class ValueMap 522 { 523 public: 524 struct MapEntry 525 { 526 const char* maKey; 527 ValueType maValue; 528 }; 529 530 /** Create a ValueMap for the given array of MapEntries. 531 532 @param pMap 533 Pointer to a <em>static</em> array of MapEntries. Must 534 live longer than this object! Make absolutely sure that 535 the string entries passed via pMap are ASCII-only - 536 everything else might not yield correct string 537 comparisons, and thus will result in undefined behaviour. 538 539 @param nEntries 540 Number of entries for pMap 541 542 @param bCaseSensitive 543 Whether the map query should be performed case sensitive 544 or not. When bCaseSensitive is false, all MapEntry strings 545 must be lowercase! 546 */ ValueMap(const MapEntry * pMap,::std::size_t nEntries,bool bCaseSensitive)547 ValueMap( const MapEntry* pMap, 548 ::std::size_t nEntries, 549 bool bCaseSensitive ) : 550 mpMap( pMap ), 551 mnEntries( nEntries ), 552 mbCaseSensitive( bCaseSensitive ) 553 { 554 #ifdef DBG_UTIL 555 // Ensure that map entries are sorted (and all lowercase, if this 556 // map is case insensitive) 557 const ::rtl::OString aStr( pMap->maKey ); 558 if( !mbCaseSensitive && 559 aStr != aStr.toAsciiLowerCase() ) 560 { 561 OSL_TRACE("ValueMap::ValueMap(): Key %s is not lowercase", 562 pMap->maKey); 563 OSL_ENSURE( false, "ValueMap::ValueMap(): Key is not lowercase" ); 564 } 565 566 if( mnEntries > 1 ) 567 { 568 for( ::std::size_t i=0; i<mnEntries-1; ++i, ++pMap ) 569 { 570 if( !mapComparator(pMap[0], pMap[1]) && 571 mapComparator(pMap[1], pMap[0]) ) 572 { 573 OSL_TRACE("ValueMap::ValueMap(): Map is not sorted, keys %s and %s are wrong", 574 pMap[0].maKey, 575 pMap[1].maKey); 576 OSL_ENSURE( false, 577 "ValueMap::ValueMap(): Map is not sorted" ); 578 } 579 580 const ::rtl::OString aStr2( pMap[1].maKey ); 581 if( !mbCaseSensitive && 582 aStr2 != aStr2.toAsciiLowerCase() ) 583 { 584 OSL_TRACE("ValueMap::ValueMap(): Key %s is not lowercase", 585 pMap[1].maKey); 586 OSL_ENSURE( false, "ValueMap::ValueMap(): Key is not lowercase" ); 587 } 588 } 589 } 590 #endif 591 } 592 593 /** Lookup a value for the given query string 594 595 @param rName 596 The string to lookup. If the map was created with the case 597 insensitive flag, the lookup is performed 598 case-insensitive, otherwise, case-sensitive. 599 600 @param o_rResult 601 Output parameter, which receives the value associated with 602 the query string. If no value was found, the referenced 603 object is kept unmodified. 604 605 @return true, if a matching entry was found. 606 */ lookup(const::rtl::OUString & rName,ValueType & o_rResult) const607 bool lookup( const ::rtl::OUString& rName, 608 ValueType& o_rResult ) const 609 { 610 // rName is required to contain only ASCII characters. 611 // TODO(Q1): Enforce this at upper layers 612 ::rtl::OString aKey( ::rtl::OUStringToOString( mbCaseSensitive ? rName : rName.toAsciiLowerCase(), 613 RTL_TEXTENCODING_ASCII_US ) ); 614 MapEntry aSearchKey = 615 { 616 aKey.getStr(), 617 ValueType() 618 }; 619 620 const MapEntry* pRes; 621 const MapEntry* pEnd = mpMap+mnEntries; 622 if( (pRes=::std::lower_bound( mpMap, 623 pEnd, 624 aSearchKey, 625 &mapComparator )) != pEnd ) 626 { 627 // place to _insert before_ found - is it equal to 628 // the search key? 629 if( strcmp( pRes->maKey, aSearchKey.maKey ) == 0 ) 630 { 631 // yep, correct entry found 632 o_rResult = pRes->maValue; 633 return true; 634 } 635 } 636 637 // not found 638 return false; 639 } 640 641 private: mapComparator(const MapEntry & rLHS,const MapEntry & rRHS)642 static bool mapComparator( const MapEntry& rLHS, 643 const MapEntry& rRHS ) 644 { 645 return strcmp( rLHS.maKey, 646 rRHS.maKey ) < 0; 647 } 648 649 const MapEntry* mpMap; 650 ::std::size_t mnEntries; 651 bool mbCaseSensitive; 652 }; 653 } 654 } 655 656 #endif /* INCLUDED_CANVAS_CANVASTOOLS_HXX */ 657 // eof 658