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