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