xref: /trunk/main/vcl/source/gdi/impvect.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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