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