xref: /AOO41X/main/vcl/source/gdi/impvect.cxx (revision 9f62ea84a806e17e6f2bbff75724a7257a0eb5d9)
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 
operator <(const ImplColorSet & rSet) const119 inline sal_Bool ImplColorSet::operator<( const ImplColorSet& rSet ) const
120 {
121     return( mbSet && ( !rSet.mbSet || ( maColor.GetLuminance() > rSet.maColor.GetLuminance() ) ) );
122 }
123 
124 // ----------------------------------------------------------------------------
125 
operator >(const ImplColorSet & rSet) const126 inline sal_Bool ImplColorSet::operator>( const ImplColorSet& rSet ) const
127 {
128     return( !mbSet || ( rSet.mbSet && maColor.GetLuminance() < rSet.maColor.GetLuminance() ) );
129 }
130 
131 // ----------------------------------------------------------------------------
132 
ImplColorSetCmpFnc(const void * p1,const void * p2)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 
ImplGetRealSize() const172     sal_uLong               ImplGetRealSize() const { return mnRealSize; }
ImplSetRealSize(sal_uLong nRealSize)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 
ImplPointArray()183 ImplPointArray::ImplPointArray() :
184     mpArray     ( NULL ),
185     mnSize      ( 0UL ),
186     mnRealSize  ( 0UL )
187 
188 {
189 }
190 
191 // -----------------------------------------------------------------------------
192 
~ImplPointArray()193 ImplPointArray::~ImplPointArray()
194 {
195     if( mpArray )
196         rtl_freeMemory( mpArray );
197 }
198 
199 // -----------------------------------------------------------------------------
200 
ImplSetSize(sal_uLong nSize)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 
operator [](sal_uLong nPos)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 
operator [](sal_uLong nPos) const225 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 
ImplCreatePoly(Polygon & rPoly) const233 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 
ImplVectMap()251                     ImplVectMap() {};
252 
253 public:
254 
255                     ImplVectMap( long nWidth, long nHeight );
256                     ~ImplVectMap();
257 
Width() const258     inline long     Width() const { return mnWidth; }
Height() const259     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 
ImplVectMap(long nWidth,long nHeight)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 
~ImplVectMap()290 ImplVectMap::~ImplVectMap()
291 {
292     rtl_freeMemory( mpBuf );
293     rtl_freeMemory( mpScan );
294 }
295 
296 // -----------------------------------------------------------------------------
297 
Set(long nY,long nX,sal_uInt8 cVal)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 
Get(long nY,long nX) const306 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 
IsFree(long nY,long nX) const313 inline sal_Bool ImplVectMap::IsFree( long nY, long nX ) const
314 {
315     return( VECT_FREE_INDEX == Get( nY, nX ) );
316 }
317 
318 // -----------------------------------------------------------------------------
319 
IsCont(long nY,long nX) const320 inline sal_Bool ImplVectMap::IsCont( long nY, long nX ) const
321 {
322     return( VECT_CONT_INDEX == Get( nY, nX ) );
323 }
324 
325 // -----------------------------------------------------------------------------
326 
IsDone(long nY,long nX) const327 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 
ImplGetPoly()363     const Polygon&  ImplGetPoly() { return maPoly; }
364 };
365 
366 // -----------------------------------------------------------------------------
367 
ImplChain(sal_uLong nInitCount,long nResize)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 
~ImplChain()379 ImplChain::~ImplChain()
380 {
381     delete[] mpCodes;
382 }
383 
384 // -----------------------------------------------------------------------------
385 
ImplGetSpace()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 
ImplBeginAdd(const Point & rStartPt)400 void ImplChain::ImplBeginAdd( const Point& rStartPt )
401 {
402     maPoly = Polygon();
403     maStartPt = rStartPt;
404     mnCount = 0UL;
405 }
406 
407 // -----------------------------------------------------------------------------
408 
ImplAdd(sal_uInt8 nCode)409 inline void ImplChain::ImplAdd( sal_uInt8 nCode )
410 {
411     if( mnCount == mnArraySize )
412         ImplGetSpace();
413 
414     mpCodes[ mnCount++ ] = nCode;
415 }
416 
417 // -----------------------------------------------------------------------------
418 
ImplEndAdd(sal_uLong nFlag)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 
ImplPostProcess(const ImplPointArray & rArr)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 
ImplVectorizer()726 ImplVectorizer::ImplVectorizer()
727 {
728 }
729 
730 // -----------------------------------------------------------------------------
731 
~ImplVectorizer()732 ImplVectorizer::~ImplVectorizer()
733 {
734 }
735 
736 // -----------------------------------------------------------------------------
737 
ImplVectorize(const Bitmap & rColorBmp,GDIMetaFile & rMtf,sal_uInt8 cReduce,sal_uLong nFlags,const Link * pProgress)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 
ImplVectorize(const Bitmap & rMonoBmp,PolyPolygon & rPolyPoly,sal_uLong nFlags,const Link * pProgress)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 
ImplLimitPolyPoly(PolyPolygon & rPolyPoly)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 
ImplExpand(BitmapReadAccess * pRAcc,const Color & rColor)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 
ImplCalculate(ImplVectMap * pMap,PolyPolygon & rPolyPoly,sal_uInt8 cReduce,sal_uLong nFlags)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 
ImplGetChain(ImplVectMap * pMap,const Point & rStartPt,ImplChain & rChain)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 
ImplIsUp(ImplVectMap * pMap,long nY,long nX) const1190 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