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_vcl.hxx" 30 31 #include <stdlib.h> 32 #include <vcl/bmpacc.hxx> 33 #include <tools/poly.hxx> 34 #include <vcl/gdimtf.hxx> 35 #include <vcl/metaact.hxx> 36 #include <vcl/svapp.hxx> 37 #include <vcl/wrkwin.hxx> 38 #include <vcl/virdev.hxx> 39 #ifndef _SV_VECTORIZ_HXX 40 #include <impvect.hxx> 41 #endif 42 43 // ----------- 44 // - Defines - 45 // ----------- 46 47 #define VECT_POLY_MAX 8192 48 49 // ----------------------------------------------------------------------------- 50 51 #define VECT_FREE_INDEX 0 52 #define VECT_CONT_INDEX 1 53 #define VECT_DONE_INDEX 2 54 55 // ----------------------------------------------------------------------------- 56 57 #define VECT_POLY_INLINE_INNER 1UL 58 #define VECT_POLY_INLINE_OUTER 2UL 59 #define VECT_POLY_OUTLINE_INNER 4UL 60 #define VECT_POLY_OUTLINE_OUTER 8UL 61 62 // ----------------------------------------------------------------------------- 63 64 #define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4L)+1L)+5L; 65 #define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1) 66 #define VECT_PROGRESS( _def_pProgress, _def_nVal ) if(_def_pProgress&&_def_pProgress->IsSet())(_def_pProgress->Call((void*)_def_nVal)); 67 68 // ----------- 69 // - statics - 70 // ----------- 71 72 struct ChainMove { long nDX; long nDY; }; 73 74 static ChainMove aImplMove[ 8 ] = { 75 { 1L, 0L }, 76 { 0L, -1L }, 77 { -1L, 0L }, 78 { 0L, 1L }, 79 { 1L, -1L }, 80 { -1, -1L }, 81 { -1L, 1L }, 82 { 1L, 1L } 83 }; 84 85 static ChainMove aImplMoveInner[ 8 ] = { 86 { 0L, 1L }, 87 { 1L, 0L }, 88 { 0L, -1L }, 89 { -1L, 0L }, 90 { 0L, 1L }, 91 { 1L, 0L }, 92 { 0L, -1L }, 93 { -1L, 0L } 94 }; 95 96 static ChainMove aImplMoveOuter[ 8 ] = { 97 { 0L, -1L }, 98 { -1L, 0L }, 99 { 0L, 1L }, 100 { 1L, 0L }, 101 { -1L, 0L }, 102 { 0L, 1L }, 103 { 1L, 0L }, 104 { 0L, -1L } 105 }; 106 107 // ---------------- 108 // - ImplColorSet - 109 // ---------------- 110 111 struct ImplColorSet 112 { 113 BitmapColor maColor; 114 sal_uInt16 mnIndex; 115 sal_Bool mbSet; 116 117 sal_Bool operator<( const ImplColorSet& rSet ) const; 118 sal_Bool operator>( const ImplColorSet& rSet ) const; 119 }; 120 121 // ---------------------------------------------------------------------------- 122 123 inline sal_Bool ImplColorSet::operator<( const ImplColorSet& rSet ) const 124 { 125 return( mbSet && ( !rSet.mbSet || ( maColor.GetLuminance() > rSet.maColor.GetLuminance() ) ) ); 126 } 127 128 // ---------------------------------------------------------------------------- 129 130 inline sal_Bool ImplColorSet::operator>( const ImplColorSet& rSet ) const 131 { 132 return( !mbSet || ( rSet.mbSet && maColor.GetLuminance() < rSet.maColor.GetLuminance() ) ); 133 } 134 135 // ---------------------------------------------------------------------------- 136 137 extern "C" int __LOADONCALLAPI ImplColorSetCmpFnc( const void* p1, const void* p2 ) 138 { 139 ImplColorSet* pSet1 = (ImplColorSet*) p1; 140 ImplColorSet* pSet2 = (ImplColorSet*) p2; 141 int nRet; 142 143 if( pSet1->mbSet && pSet2->mbSet ) 144 { 145 const sal_uInt8 cLum1 = pSet1->maColor.GetLuminance(); 146 const sal_uInt8 cLum2 = pSet2->maColor.GetLuminance(); 147 nRet = ( ( cLum1 > cLum2 ) ? -1 : ( ( cLum1 == cLum2 ) ? 0 : 1 ) ); 148 } 149 else if( pSet1->mbSet ) 150 nRet = -1; 151 else if( pSet2->mbSet ) 152 nRet = 1; 153 else 154 nRet = 0; 155 156 return nRet; 157 } 158 159 // ------------------ 160 // - ImplPointArray - 161 // ------------------ 162 163 class ImplPointArray 164 { 165 Point* mpArray; 166 sal_uLong mnSize; 167 sal_uLong mnRealSize; 168 169 public: 170 171 ImplPointArray(); 172 ~ImplPointArray(); 173 174 void ImplSetSize( sal_uLong nSize ); 175 176 sal_uLong ImplGetRealSize() const { return mnRealSize; } 177 void ImplSetRealSize( sal_uLong nRealSize ) { mnRealSize = nRealSize; } 178 179 inline Point& operator[]( sal_uLong nPos ); 180 inline const Point& operator[]( sal_uLong nPos ) const; 181 182 void ImplCreatePoly( Polygon& rPoly ) const; 183 }; 184 185 // ----------------------------------------------------------------------------- 186 187 ImplPointArray::ImplPointArray() : 188 mpArray ( NULL ), 189 mnSize ( 0UL ), 190 mnRealSize ( 0UL ) 191 192 { 193 } 194 195 // ----------------------------------------------------------------------------- 196 197 ImplPointArray::~ImplPointArray() 198 { 199 if( mpArray ) 200 rtl_freeMemory( mpArray ); 201 } 202 203 // ----------------------------------------------------------------------------- 204 205 void ImplPointArray::ImplSetSize( sal_uLong nSize ) 206 { 207 const sal_uLong nTotal = nSize * sizeof( Point ); 208 209 mnSize = nSize; 210 mnRealSize = 0UL; 211 212 if( mpArray ) 213 rtl_freeMemory( mpArray ); 214 215 mpArray = (Point*) rtl_allocateMemory( nTotal ); 216 memset( (HPBYTE) mpArray, 0, nTotal ); 217 } 218 219 // ----------------------------------------------------------------------------- 220 221 inline Point& ImplPointArray::operator[]( sal_uLong nPos ) 222 { 223 DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" ); 224 return mpArray[ nPos ]; 225 } 226 227 // ----------------------------------------------------------------------------- 228 229 inline const Point& ImplPointArray::operator[]( sal_uLong nPos ) const 230 { 231 DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" ); 232 return mpArray[ nPos ]; 233 } 234 235 // ----------------------------------------------------------------------------- 236 237 void ImplPointArray::ImplCreatePoly( Polygon& rPoly ) const 238 { 239 rPoly = Polygon( sal::static_int_cast<sal_uInt16>(mnRealSize), mpArray ); 240 } 241 242 // --------------- 243 // - ImplVectMap - 244 // --------------- 245 246 class ImplVectMap 247 { 248 private: 249 250 Scanline mpBuf; 251 Scanline* mpScan; 252 long mnWidth; 253 long mnHeight; 254 255 ImplVectMap() {}; 256 257 public: 258 259 ImplVectMap( long nWidth, long nHeight ); 260 ~ImplVectMap(); 261 262 inline long Width() const { return mnWidth; } 263 inline long Height() const { return mnHeight; } 264 265 inline void Set( long nY, long nX, sal_uInt8 cVal ); 266 inline sal_uInt8 Get( long nY, long nX ) const; 267 268 inline sal_Bool IsFree( long nY, long nX ) const; 269 inline sal_Bool IsCont( long nY, long nX ) const; 270 inline sal_Bool IsDone( long nY, long nX ) const; 271 272 }; 273 274 // ----------------------------------------------------------------------------- 275 276 ImplVectMap::ImplVectMap( long nWidth, long nHeight ) : 277 mnWidth ( nWidth ), 278 mnHeight( nHeight ) 279 { 280 const long nWidthAl = ( nWidth >> 2L ) + 1L; 281 const long nSize = nWidthAl * nHeight; 282 Scanline pTmp = mpBuf = (Scanline) rtl_allocateMemory( nSize ); 283 284 memset( mpBuf, 0, nSize ); 285 mpScan = (Scanline*) rtl_allocateMemory( nHeight * sizeof( Scanline ) ); 286 287 for( long nY = 0L; nY < nHeight; pTmp += nWidthAl ) 288 mpScan[ nY++ ] = pTmp; 289 } 290 291 // ----------------------------------------------------------------------------- 292 293 294 ImplVectMap::~ImplVectMap() 295 { 296 rtl_freeMemory( mpBuf ); 297 rtl_freeMemory( mpScan ); 298 } 299 300 // ----------------------------------------------------------------------------- 301 302 inline void ImplVectMap::Set( long nY, long nX, sal_uInt8 cVal ) 303 { 304 const sal_uInt8 cShift = sal::static_int_cast<sal_uInt8>(6 - ( ( nX & 3 ) << 1 )); 305 ( ( mpScan[ nY ][ nX >> 2 ] ) &= ~( 3 << cShift ) ) |= ( cVal << cShift ); 306 } 307 308 // ----------------------------------------------------------------------------- 309 310 inline sal_uInt8 ImplVectMap::Get( long nY, long nX ) const 311 { 312 return sal::static_int_cast<sal_uInt8>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 ); 313 } 314 315 // ----------------------------------------------------------------------------- 316 317 inline sal_Bool ImplVectMap::IsFree( long nY, long nX ) const 318 { 319 return( VECT_FREE_INDEX == Get( nY, nX ) ); 320 } 321 322 // ----------------------------------------------------------------------------- 323 324 inline sal_Bool ImplVectMap::IsCont( long nY, long nX ) const 325 { 326 return( VECT_CONT_INDEX == Get( nY, nX ) ); 327 } 328 329 // ----------------------------------------------------------------------------- 330 331 inline sal_Bool ImplVectMap::IsDone( long nY, long nX ) const 332 { 333 return( VECT_DONE_INDEX == Get( nY, nX ) ); 334 } 335 336 // ------------- 337 // - ImplChain - 338 // ------------- 339 340 class ImplChain 341 { 342 private: 343 344 Polygon maPoly; 345 Point maStartPt; 346 sal_uLong mnArraySize; 347 sal_uLong mnCount; 348 long mnResize; 349 sal_uInt8* mpCodes; 350 351 void ImplGetSpace(); 352 353 void ImplCreate(); 354 void ImplCreateInner(); 355 void ImplCreateOuter(); 356 void ImplPostProcess( const ImplPointArray& rArr ); 357 358 public: 359 360 ImplChain( sal_uLong nInitCount = 1024UL, long nResize = -1L ); 361 ~ImplChain(); 362 363 void ImplBeginAdd( const Point& rStartPt ); 364 inline void ImplAdd( sal_uInt8 nCode ); 365 void ImplEndAdd( sal_uLong nTypeFlag ); 366 367 const Polygon& ImplGetPoly() { return maPoly; } 368 }; 369 370 // ----------------------------------------------------------------------------- 371 372 ImplChain::ImplChain( sal_uLong nInitCount, long nResize ) : 373 mnArraySize ( nInitCount ), 374 mnCount ( 0UL ), 375 mnResize ( nResize ) 376 { 377 DBG_ASSERT( nInitCount && nResize, "ImplChain::ImplChain(): invalid parameters!" ); 378 mpCodes = new sal_uInt8[ mnArraySize ]; 379 } 380 381 // ----------------------------------------------------------------------------- 382 383 ImplChain::~ImplChain() 384 { 385 delete[] mpCodes; 386 } 387 388 // ----------------------------------------------------------------------------- 389 390 void ImplChain::ImplGetSpace() 391 { 392 const sal_uLong nOldArraySize = mnArraySize; 393 sal_uInt8* pNewCodes; 394 395 mnArraySize = ( mnResize < 0L ) ? ( mnArraySize << 1UL ) : ( mnArraySize + (sal_uLong) mnResize ); 396 pNewCodes = new sal_uInt8[ mnArraySize ]; 397 memcpy( pNewCodes, mpCodes, nOldArraySize ); 398 delete[] mpCodes; 399 mpCodes = pNewCodes; 400 } 401 402 // ----------------------------------------------------------------------------- 403 404 void ImplChain::ImplBeginAdd( const Point& rStartPt ) 405 { 406 maPoly = Polygon(); 407 maStartPt = rStartPt; 408 mnCount = 0UL; 409 } 410 411 // ----------------------------------------------------------------------------- 412 413 inline void ImplChain::ImplAdd( sal_uInt8 nCode ) 414 { 415 if( mnCount == mnArraySize ) 416 ImplGetSpace(); 417 418 mpCodes[ mnCount++ ] = nCode; 419 } 420 421 // ----------------------------------------------------------------------------- 422 423 void ImplChain::ImplEndAdd( sal_uLong nFlag ) 424 { 425 if( mnCount ) 426 { 427 ImplPointArray aArr; 428 429 if( nFlag & VECT_POLY_INLINE_INNER ) 430 { 431 long nFirstX, nFirstY; 432 long nLastX, nLastY; 433 434 nFirstX = nLastX = maStartPt.X(); 435 nFirstY = nLastY = maStartPt.Y(); 436 aArr.ImplSetSize( mnCount << 1 ); 437 438 sal_uInt16 i, nPolyPos; 439 for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ ) 440 { 441 const sal_uInt8 cMove = mpCodes[ i ]; 442 const sal_uInt8 cNextMove = mpCodes[ i + 1 ]; 443 const ChainMove& rMove = aImplMove[ cMove ]; 444 const ChainMove& rMoveInner = aImplMoveInner[ cMove ]; 445 // Point& rPt = aArr[ nPolyPos ]; 446 sal_Bool bDone = sal_True; 447 448 nLastX += rMove.nDX; 449 nLastY += rMove.nDY; 450 451 if( cMove < 4 ) 452 { 453 if( ( cMove == 0 && cNextMove == 3 ) || 454 ( cMove == 3 && cNextMove == 2 ) || 455 ( cMove == 2 && cNextMove == 1 ) || 456 ( cMove == 1 && cNextMove == 0 ) ) 457 { 458 } 459 else if( cMove == 2 && cNextMove == 3 ) 460 { 461 aArr[ nPolyPos ].X() = nLastX; 462 aArr[ nPolyPos++ ].Y() = nLastY - 1; 463 464 aArr[ nPolyPos ].X() = nLastX - 1; 465 aArr[ nPolyPos++ ].Y() = nLastY - 1; 466 467 aArr[ nPolyPos ].X() = nLastX - 1; 468 aArr[ nPolyPos++ ].Y() = nLastY; 469 } 470 else if( cMove == 3 && cNextMove == 0 ) 471 { 472 aArr[ nPolyPos ].X() = nLastX - 1; 473 aArr[ nPolyPos++ ].Y() = nLastY; 474 475 aArr[ nPolyPos ].X() = nLastX - 1; 476 aArr[ nPolyPos++ ].Y() = nLastY + 1; 477 478 aArr[ nPolyPos ].X() = nLastX; 479 aArr[ nPolyPos++ ].Y() = nLastY + 1; 480 } 481 else if( cMove == 0 && cNextMove == 1 ) 482 { 483 aArr[ nPolyPos ].X() = nLastX; 484 aArr[ nPolyPos++ ].Y() = nLastY + 1; 485 486 aArr[ nPolyPos ].X() = nLastX + 1; 487 aArr[ nPolyPos++ ].Y() = nLastY + 1; 488 489 aArr[ nPolyPos ].X() = nLastX + 1; 490 aArr[ nPolyPos++ ].Y() = nLastY; 491 } 492 else if( cMove == 1 && cNextMove == 2 ) 493 { 494 aArr[ nPolyPos ].X() = nLastX + 1; 495 aArr[ nPolyPos++ ].Y() = nLastY + 1; 496 497 aArr[ nPolyPos ].X() = nLastX + 1; 498 aArr[ nPolyPos++ ].Y() = nLastY - 1; 499 500 aArr[ nPolyPos ].X() = nLastX; 501 aArr[ nPolyPos++ ].Y() = nLastY - 1; 502 } 503 else 504 bDone = sal_False; 505 } 506 else if( cMove == 7 && cNextMove == 0 ) 507 { 508 aArr[ nPolyPos ].X() = nLastX - 1; 509 aArr[ nPolyPos++ ].Y() = nLastY; 510 511 aArr[ nPolyPos ].X() = nLastX; 512 aArr[ nPolyPos++ ].Y() = nLastY + 1; 513 } 514 else if( cMove == 4 && cNextMove == 1 ) 515 { 516 aArr[ nPolyPos ].X() = nLastX; 517 aArr[ nPolyPos++ ].Y() = nLastY + 1; 518 519 aArr[ nPolyPos ].X() = nLastX + 1; 520 aArr[ nPolyPos++ ].Y() = nLastY; 521 } 522 else 523 bDone = sal_False; 524 525 if( !bDone ) 526 { 527 aArr[ nPolyPos ].X() = nLastX + rMoveInner.nDX; 528 aArr[ nPolyPos++ ].Y() = nLastY + rMoveInner.nDY; 529 } 530 } 531 532 aArr[ nPolyPos ].X() = nFirstX + 1L; 533 aArr[ nPolyPos++ ].Y() = nFirstY + 1L; 534 aArr.ImplSetRealSize( nPolyPos ); 535 } 536 else if( nFlag & VECT_POLY_INLINE_OUTER ) 537 { 538 long nFirstX, nFirstY; 539 long nLastX, nLastY; 540 541 nFirstX = nLastX = maStartPt.X(); 542 nFirstY = nLastY = maStartPt.Y(); 543 aArr.ImplSetSize( mnCount << 1 ); 544 545 sal_uInt16 i, nPolyPos; 546 for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ ) 547 { 548 const sal_uInt8 cMove = mpCodes[ i ]; 549 const sal_uInt8 cNextMove = mpCodes[ i + 1 ]; 550 const ChainMove& rMove = aImplMove[ cMove ]; 551 const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ]; 552 // Point& rPt = aArr[ nPolyPos ]; 553 sal_Bool bDone = sal_True; 554 555 nLastX += rMove.nDX; 556 nLastY += rMove.nDY; 557 558 if( cMove < 4 ) 559 { 560 if( ( cMove == 0 && cNextMove == 1 ) || 561 ( cMove == 1 && cNextMove == 2 ) || 562 ( cMove == 2 && cNextMove == 3 ) || 563 ( cMove == 3 && cNextMove == 0 ) ) 564 { 565 } 566 else if( cMove == 0 && cNextMove == 3 ) 567 { 568 aArr[ nPolyPos ].X() = nLastX; 569 aArr[ nPolyPos++ ].Y() = nLastY - 1; 570 571 aArr[ nPolyPos ].X() = nLastX + 1; 572 aArr[ nPolyPos++ ].Y() = nLastY - 1; 573 574 aArr[ nPolyPos ].X() = nLastX + 1; 575 aArr[ nPolyPos++ ].Y() = nLastY; 576 } 577 else if( cMove == 3 && cNextMove == 2 ) 578 { 579 aArr[ nPolyPos ].X() = nLastX + 1; 580 aArr[ nPolyPos++ ].Y() = nLastY; 581 582 aArr[ nPolyPos ].X() = nLastX + 1; 583 aArr[ nPolyPos++ ].Y() = nLastY + 1; 584 585 aArr[ nPolyPos ].X() = nLastX; 586 aArr[ nPolyPos++ ].Y() = nLastY + 1; 587 } 588 else if( cMove == 2 && cNextMove == 1 ) 589 { 590 aArr[ nPolyPos ].X() = nLastX; 591 aArr[ nPolyPos++ ].Y() = nLastY + 1; 592 593 aArr[ nPolyPos ].X() = nLastX - 1; 594 aArr[ nPolyPos++ ].Y() = nLastY + 1; 595 596 aArr[ nPolyPos ].X() = nLastX - 1; 597 aArr[ nPolyPos++ ].Y() = nLastY; 598 } 599 else if( cMove == 1 && cNextMove == 0 ) 600 { 601 aArr[ nPolyPos ].X() = nLastX - 1; 602 aArr[ nPolyPos++ ].Y() = nLastY; 603 604 aArr[ nPolyPos ].X() = nLastX - 1; 605 aArr[ nPolyPos++ ].Y() = nLastY - 1; 606 607 aArr[ nPolyPos ].X() = nLastX; 608 aArr[ nPolyPos++ ].Y() = nLastY - 1; 609 } 610 else 611 bDone = sal_False; 612 } 613 else if( cMove == 7 && cNextMove == 3 ) 614 { 615 aArr[ nPolyPos ].X() = nLastX; 616 aArr[ nPolyPos++ ].Y() = nLastY - 1; 617 618 aArr[ nPolyPos ].X() = nLastX + 1; 619 aArr[ nPolyPos++ ].Y() = nLastY; 620 } 621 else if( cMove == 6 && cNextMove == 2 ) 622 { 623 aArr[ nPolyPos ].X() = nLastX + 1; 624 aArr[ nPolyPos++ ].Y() = nLastY; 625 626 aArr[ nPolyPos ].X() = nLastX; 627 aArr[ nPolyPos++ ].Y() = nLastY + 1; 628 } 629 else 630 bDone = sal_False; 631 632 if( !bDone ) 633 { 634 aArr[ nPolyPos ].X() = nLastX + rMoveOuter.nDX; 635 aArr[ nPolyPos++ ].Y() = nLastY + rMoveOuter.nDY; 636 } 637 } 638 639 aArr[ nPolyPos ].X() = nFirstX - 1L; 640 aArr[ nPolyPos++ ].Y() = nFirstY - 1L; 641 aArr.ImplSetRealSize( nPolyPos ); 642 } 643 else 644 { 645 long nLastX = maStartPt.X(), nLastY = maStartPt.Y(); 646 647 aArr.ImplSetSize( mnCount + 1 ); 648 aArr[ 0 ] = Point( nLastX, nLastY ); 649 650 for( sal_uLong i = 0; i < mnCount; ) 651 { 652 const ChainMove& rMove = aImplMove[ mpCodes[ i ] ]; 653 aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY ); 654 } 655 656 aArr.ImplSetRealSize( mnCount + 1 ); 657 } 658 659 ImplPostProcess( aArr ); 660 } 661 else 662 maPoly.SetSize( 0 ); 663 } 664 665 // ----------------------------------------------------------------------------- 666 667 void ImplChain::ImplPostProcess( const ImplPointArray& rArr ) 668 { 669 ImplPointArray aNewArr1; 670 ImplPointArray aNewArr2; 671 Point* pLast; 672 Point* pLeast; 673 sal_uLong nNewPos; 674 sal_uLong nCount = rArr.ImplGetRealSize(); 675 sal_uLong n; 676 677 // pass 1 678 aNewArr1.ImplSetSize( nCount ); 679 pLast = &( aNewArr1[ 0 ] ); 680 pLast->X() = BACK_MAP( rArr[ 0 ].X() ); 681 pLast->Y() = BACK_MAP( rArr[ 0 ].Y() ); 682 683 for( n = nNewPos = 1; n < nCount; ) 684 { 685 const Point& rPt = rArr[ n++ ]; 686 const long nX = BACK_MAP( rPt.X() ); 687 const long nY = BACK_MAP( rPt.Y() ); 688 689 if( nX != pLast->X() || nY != pLast->Y() ) 690 { 691 pLast = pLeast = &( aNewArr1[ nNewPos++ ] ); 692 pLeast->X() = nX; 693 pLeast->Y() = nY; 694 } 695 } 696 697 aNewArr1.ImplSetRealSize( nCount = nNewPos ); 698 699 // pass 2 700 aNewArr2.ImplSetSize( nCount ); 701 pLast = &( aNewArr2[ 0 ] ); 702 *pLast = aNewArr1[ 0 ]; 703 704 for( n = nNewPos = 1; n < nCount; ) 705 { 706 pLeast = &( aNewArr1[ n++ ] ); 707 708 if( pLeast->X() == pLast->X() ) 709 { 710 while( n < nCount && aNewArr1[ n ].X() == pLast->X() ) 711 pLeast = &( aNewArr1[ n++ ] ); 712 } 713 else if( pLeast->Y() == pLast->Y() ) 714 { 715 while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() ) 716 pLeast = &( aNewArr1[ n++ ] ); 717 } 718 719 aNewArr2[ nNewPos++ ] = *( pLast = pLeast ); 720 } 721 722 aNewArr2.ImplSetRealSize( nNewPos ); 723 aNewArr2.ImplCreatePoly( maPoly ); 724 } 725 726 // ------------------ 727 // - ImplVectorizer - 728 // ------------------ 729 730 ImplVectorizer::ImplVectorizer() 731 { 732 } 733 734 // ----------------------------------------------------------------------------- 735 736 ImplVectorizer::~ImplVectorizer() 737 { 738 } 739 740 // ----------------------------------------------------------------------------- 741 742 sal_Bool ImplVectorizer::ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf, 743 sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress ) 744 { 745 sal_Bool bRet = sal_False; 746 747 VECT_PROGRESS( pProgress, 0 ); 748 749 Bitmap* pBmp = new Bitmap( rColorBmp ); 750 BitmapReadAccess* pRAcc = pBmp->AcquireReadAccess(); 751 752 if( pRAcc ) 753 { 754 PolyPolygon aPolyPoly; 755 double fPercent = 0.0; 756 double fPercentStep_2 = 0.0; 757 const long nWidth = pRAcc->Width(); 758 const long nHeight = pRAcc->Height(); 759 const sal_uInt16 nColorCount = pRAcc->GetPaletteEntryCount(); 760 sal_uInt16 n; 761 ImplColorSet* pColorSet = (ImplColorSet*) new sal_uInt8[ 256 * sizeof( ImplColorSet ) ]; 762 763 memset( pColorSet, 0, 256 * sizeof( ImplColorSet ) ); 764 rMtf.Clear(); 765 766 // get used palette colors and sort them from light to dark colors 767 for( n = 0; n < nColorCount; n++ ) 768 { 769 pColorSet[ n ].mnIndex = n; 770 pColorSet[ n ].maColor = pRAcc->GetPaletteColor( n ); 771 } 772 773 for( long nY = 0L; nY < nHeight; nY++ ) 774 for( long nX = 0L; nX < nWidth; nX++ ) 775 pColorSet[ pRAcc->GetPixel( nY, nX ).GetIndex() ].mbSet = 1; 776 777 qsort( pColorSet, 256, sizeof( ImplColorSet ), ImplColorSetCmpFnc ); 778 779 for( n = 0; n < 256; n++ ) 780 if( !pColorSet[ n ].mbSet ) 781 break; 782 783 if( n ) 784 fPercentStep_2 = 45.0 / n; 785 786 VECT_PROGRESS( pProgress, FRound( fPercent += 10.0 ) ); 787 788 for( sal_uInt16 i = 0; i < n; i++ ) 789 { 790 const BitmapColor aBmpCol( pRAcc->GetPaletteColor( pColorSet[ i ].mnIndex ) ); 791 const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() ); 792 // const sal_uInt8 cLum = aFindColor.GetLuminance(); 793 ImplVectMap* pMap = ImplExpand( pRAcc, aFindColor ); 794 795 VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) ); 796 797 if( pMap ) 798 { 799 aPolyPoly.Clear(); 800 ImplCalculate( pMap, aPolyPoly, cReduce, nFlags ); 801 delete pMap; 802 803 if( aPolyPoly.Count() ) 804 { 805 ImplLimitPolyPoly( aPolyPoly ); 806 807 if( nFlags & BMP_VECTORIZE_REDUCE_EDGES ) 808 aPolyPoly.Optimize( POLY_OPTIMIZE_EDGES ); 809 810 if( aPolyPoly.Count() ) 811 { 812 rMtf.AddAction( new MetaLineColorAction( aFindColor, sal_True ) ); 813 rMtf.AddAction( new MetaFillColorAction( aFindColor, sal_True ) ); 814 rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); 815 } 816 } 817 } 818 819 VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) ); 820 } 821 822 delete[] (sal_uInt8*) pColorSet; 823 824 if( rMtf.GetActionCount() ) 825 { 826 MapMode aMap( MAP_100TH_MM ); 827 VirtualDevice aVDev; 828 const Size aLogSize1( aVDev.PixelToLogic( Size( 1, 1 ), aMap ) ); 829 830 rMtf.SetPrefMapMode( aMap ); 831 rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) ); 832 rMtf.Move( 1, 1 ); 833 rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() ); 834 bRet = sal_True; 835 } 836 } 837 838 pBmp->ReleaseAccess( pRAcc ); 839 delete pBmp; 840 VECT_PROGRESS( pProgress, 100 ); 841 842 return bRet; 843 } 844 845 // ----------------------------------------------------------------------------- 846 847 sal_Bool ImplVectorizer::ImplVectorize( const Bitmap& rMonoBmp, 848 PolyPolygon& rPolyPoly, 849 sal_uLong nFlags, const Link* pProgress ) 850 { 851 Bitmap* pBmp = new Bitmap( rMonoBmp ); 852 BitmapReadAccess* pRAcc; 853 ImplVectMap* pMap; 854 sal_Bool bRet = sal_False; 855 856 VECT_PROGRESS( pProgress, 10 ); 857 858 if( pBmp->GetBitCount() > 1 ) 859 pBmp->Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 860 861 VECT_PROGRESS( pProgress, 30 ); 862 863 pRAcc = pBmp->AcquireReadAccess(); 864 pMap = ImplExpand( pRAcc, COL_BLACK ); 865 pBmp->ReleaseAccess( pRAcc ); 866 delete pBmp; 867 868 VECT_PROGRESS( pProgress, 60 ); 869 870 if( pMap ) 871 { 872 rPolyPoly.Clear(); 873 ImplCalculate( pMap, rPolyPoly, 0, nFlags ); 874 delete pMap; 875 ImplLimitPolyPoly( rPolyPoly ); 876 877 if( nFlags & BMP_VECTORIZE_REDUCE_EDGES ) 878 rPolyPoly.Optimize( POLY_OPTIMIZE_EDGES ); 879 880 // #i14895#:setting the correct direction for polygons 881 // that represent holes and non-holes; non-hole polygons 882 // need to have a right orientation, holes need to have a 883 // left orientation in order to be treated correctly by 884 // several external tools like Flash viewers 885 sal_Int32 nFirstPoly = -1; 886 sal_uInt16 nCurPoly( 0 ), nCount( rPolyPoly.Count() ); 887 888 for( ; nCurPoly < nCount; ++nCurPoly ) 889 { 890 const Polygon& rPoly = rPolyPoly.GetObject( nCurPoly ); 891 const sal_uInt16 nSize( rPoly.GetSize() ); 892 sal_uInt16 nDepth( 0 ), i( 0 ); 893 const bool bRight( rPoly.IsRightOrientated() ); 894 895 for( ; i < nCount; ++i ) 896 if( ( i != nCurPoly ) && rPolyPoly.GetObject( i ).IsInside( rPoly[ 0 ] ) ) 897 ++nDepth; 898 899 const bool bHole( ( nDepth & 0x0001 ) == 1 ); 900 901 if( nSize && ( ( !bRight && !bHole ) || ( bRight && bHole ) ) ) 902 { 903 Polygon aNewPoly( nSize ); 904 sal_uInt16 nPrim( 0 ), nSec( nSize - 1 ); 905 906 if( rPoly.HasFlags() ) 907 { 908 while( nPrim < nSize ) 909 { 910 aNewPoly.SetPoint( rPoly.GetPoint( nSec ), nPrim ); 911 aNewPoly.SetFlags( nPrim++, rPoly.GetFlags( nSec-- ) ); 912 } 913 } 914 else 915 while( nPrim < nSize ) 916 aNewPoly.SetPoint( rPoly.GetPoint( nSec-- ), nPrim++ ); 917 918 rPolyPoly.Replace( aNewPoly, nCurPoly ); 919 } 920 921 if( ( 0 == nDepth ) && ( -1 == nFirstPoly ) ) 922 nFirstPoly = nCurPoly; 923 } 924 925 // put outmost polygon to the front 926 if( nFirstPoly > 0 ) 927 { 928 const Polygon aFirst( rPolyPoly.GetObject( static_cast< sal_uInt16 >( nFirstPoly ) ) ); 929 930 rPolyPoly.Remove( static_cast< sal_uInt16 >( nFirstPoly ) ); 931 rPolyPoly.Insert( aFirst, 0 ); 932 } 933 934 bRet = sal_True; 935 } 936 937 VECT_PROGRESS( pProgress, 100 ); 938 939 return bRet; 940 } 941 942 // ----------------------------------------------------------------------------- 943 944 void ImplVectorizer::ImplLimitPolyPoly( PolyPolygon& rPolyPoly ) 945 { 946 if( rPolyPoly.Count() > VECT_POLY_MAX ) 947 { 948 PolyPolygon aNewPolyPoly; 949 long nReduce = 0; 950 sal_uInt16 nNewCount; 951 952 do 953 { 954 aNewPolyPoly.Clear(); 955 nReduce++; 956 957 for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ ) 958 { 959 const Rectangle aBound( rPolyPoly[ i ].GetBoundRect() ); 960 961 if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce ) 962 { 963 if( rPolyPoly[ i ].GetSize() ) 964 aNewPolyPoly.Insert( rPolyPoly[ i ] ); 965 } 966 } 967 968 nNewCount = aNewPolyPoly.Count(); 969 } 970 while( nNewCount > VECT_POLY_MAX ); 971 972 rPolyPoly = aNewPolyPoly; 973 } 974 } 975 976 // ----------------------------------------------------------------------------- 977 978 ImplVectMap* ImplVectorizer::ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor ) 979 { 980 ImplVectMap* pMap = NULL; 981 982 if( pRAcc && pRAcc->Width() && pRAcc->Height() ) 983 { 984 const long nOldWidth = pRAcc->Width(); 985 const long nOldHeight = pRAcc->Height(); 986 const long nNewWidth = ( nOldWidth << 2L ) + 4L; 987 const long nNewHeight = ( nOldHeight << 2L ) + 4L; 988 const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) ); 989 long* pMapIn = new long[ Max( nOldWidth, nOldHeight ) ]; 990 long* pMapOut = new long[ Max( nOldWidth, nOldHeight ) ]; 991 long nX, nY, nTmpX, nTmpY; 992 993 pMap = new ImplVectMap( nNewWidth, nNewHeight ); 994 995 for( nX = 0L; nX < nOldWidth; nX++ ) 996 VECT_MAP( pMapIn, pMapOut, nX ); 997 998 for( nY = 0L, nTmpY = 5L; nY < nOldHeight; nY++, nTmpY += 4L ) 999 { 1000 for( nX = 0L; nX < nOldWidth; ) 1001 { 1002 if( pRAcc->GetPixel( nY, nX ) == aTest ) 1003 { 1004 nTmpX = pMapIn[ nX++ ]; 1005 nTmpY -= 3L; 1006 1007 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); 1008 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); 1009 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); 1010 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); 1011 1012 while( nX < nOldWidth && pRAcc->GetPixel( nY, nX ) == aTest ) 1013 nX++; 1014 1015 nTmpX = pMapOut[ nX - 1L ]; 1016 nTmpY -= 3L; 1017 1018 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); 1019 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); 1020 pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); 1021 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); 1022 } 1023 else 1024 nX++; 1025 } 1026 } 1027 1028 for( nY = 0L; nY < nOldHeight; nY++ ) 1029 VECT_MAP( pMapIn, pMapOut, nY ); 1030 1031 for( nX = 0L, nTmpX = 5L; nX < nOldWidth; nX++, nTmpX += 4L ) 1032 { 1033 for( nY = 0L; nY < nOldHeight; ) 1034 { 1035 if( pRAcc->GetPixel( nY, nX ) == aTest ) 1036 { 1037 nTmpX -= 3L; 1038 nTmpY = pMapIn[ nY++ ]; 1039 1040 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); 1041 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); 1042 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); 1043 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); 1044 1045 while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest ) 1046 nY++; 1047 1048 nTmpX -= 3L; 1049 nTmpY = pMapOut[ nY - 1L ]; 1050 1051 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); 1052 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); 1053 pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); 1054 pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); 1055 } 1056 else 1057 nY++; 1058 } 1059 } 1060 1061 // cleanup 1062 delete[] pMapIn; 1063 delete[] pMapOut; 1064 } 1065 1066 return pMap; 1067 } 1068 1069 // ----------------------------------------------------------------------------- 1070 1071 void ImplVectorizer::ImplCalculate( ImplVectMap* pMap, PolyPolygon& rPolyPoly, sal_uInt8 cReduce, sal_uLong nFlags ) 1072 { 1073 const long nWidth = pMap->Width(), nHeight= pMap->Height(); 1074 1075 for( long nY = 0L; nY < nHeight; nY++ ) 1076 { 1077 long nX = 0L; 1078 sal_Bool bInner = sal_True; 1079 1080 while( nX < nWidth ) 1081 { 1082 // skip free 1083 while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) ) 1084 nX++; 1085 1086 if( nX == nWidth ) 1087 break; 1088 1089 if( pMap->IsCont( nY, nX ) ) 1090 { 1091 // new contour 1092 ImplChain aChain; 1093 const Point aStartPt( nX++, nY ); 1094 1095 // get chain code 1096 aChain.ImplBeginAdd( aStartPt ); 1097 ImplGetChain( pMap, aStartPt, aChain ); 1098 1099 if( nFlags & BMP_VECTORIZE_INNER ) 1100 aChain.ImplEndAdd( bInner ? VECT_POLY_INLINE_INNER : VECT_POLY_INLINE_OUTER ); 1101 else 1102 aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER ); 1103 1104 const Polygon& rPoly = aChain.ImplGetPoly(); 1105 1106 if( rPoly.GetSize() > 2 ) 1107 { 1108 if( cReduce ) 1109 { 1110 const Rectangle aBound( rPoly.GetBoundRect() ); 1111 1112 if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce ) 1113 rPolyPoly.Insert( rPoly ); 1114 } 1115 else 1116 rPolyPoly.Insert( rPoly ); 1117 } 1118 1119 // skip rest of detected contour 1120 while( pMap->IsCont( nY, nX ) ) 1121 nX++; 1122 } 1123 else 1124 { 1125 // process done segment 1126 const long nStartSegX = nX++; 1127 1128 while( pMap->IsDone( nY, nX ) ) 1129 nX++; 1130 1131 if( ( ( nX - nStartSegX ) == 1L ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1L ) ) ) 1132 bInner = !bInner; 1133 } 1134 } 1135 } 1136 } 1137 1138 // ----------------------------------------------------------------------------- 1139 1140 sal_Bool ImplVectorizer::ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain ) 1141 { 1142 long nActX = rStartPt.X(); 1143 long nActY = rStartPt.Y(); 1144 long nTryX; 1145 long nTryY; 1146 sal_uLong nFound; 1147 sal_uLong nLastDir = 0UL; 1148 sal_uLong nDir; 1149 1150 do 1151 { 1152 nFound = 0UL; 1153 1154 // first try last direction 1155 nTryX = nActX + aImplMove[ nLastDir ].nDX; 1156 nTryY = nActY + aImplMove[ nLastDir ].nDY; 1157 1158 if( pMap->IsCont( nTryY, nTryX ) ) 1159 { 1160 rChain.ImplAdd( (sal_uInt8) nLastDir ); 1161 pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX ); 1162 nFound = 1UL; 1163 } 1164 else 1165 { 1166 // try other directions 1167 for( nDir = 0UL; nDir < 8UL; nDir++ ) 1168 { 1169 // we already tried nLastDir 1170 if( nDir != nLastDir ) 1171 { 1172 nTryX = nActX + aImplMove[ nDir ].nDX; 1173 nTryY = nActY + aImplMove[ nDir ].nDY; 1174 1175 if( pMap->IsCont( nTryY, nTryX ) ) 1176 { 1177 rChain.ImplAdd( (sal_uInt8) nDir ); 1178 pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX ); 1179 nFound = 1UL; 1180 nLastDir = nDir; 1181 break; 1182 } 1183 } 1184 } 1185 } 1186 } 1187 while( nFound ); 1188 1189 return sal_True; 1190 } 1191 1192 // ----------------------------------------------------------------------------- 1193 1194 sal_Bool ImplVectorizer::ImplIsUp( ImplVectMap* pMap, long nY, long nX ) const 1195 { 1196 if( pMap->IsDone( nY - 1L, nX ) ) 1197 return sal_True; 1198 else if( pMap->IsDone( nY + 1L, nX ) ) 1199 return sal_False; 1200 else if( pMap->IsDone( nY - 1L, nX - 1L ) || pMap->IsDone( nY - 1L, nX + 1L ) ) 1201 return sal_True; 1202 else 1203 return sal_False; 1204 } 1205