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