Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <stdlib.h>
21 : #include <vcl/bmpacc.hxx>
22 : #include <tools/poly.hxx>
23 : #include <vcl/gdimtf.hxx>
24 : #include <vcl/metaact.hxx>
25 : #include <vcl/svapp.hxx>
26 : #include <vcl/wrkwin.hxx>
27 : #include <vcl/virdev.hxx>
28 : #include <impvect.hxx>
29 : #include <boost/scoped_array.hpp>
30 : #include <boost/scoped_ptr.hpp>
31 :
32 : #define VECT_POLY_MAX 8192
33 :
34 : #define VECT_FREE_INDEX 0
35 : #define VECT_CONT_INDEX 1
36 : #define VECT_DONE_INDEX 2
37 :
38 : #define VECT_POLY_INLINE_INNER 1UL
39 : #define VECT_POLY_INLINE_OUTER 2UL
40 : #define VECT_POLY_OUTLINE_INNER 4UL
41 : #define VECT_POLY_OUTLINE_OUTER 8UL
42 :
43 : #define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4L)+1L)+5L;
44 : #define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1)
45 : #define VECT_PROGRESS( _def_pProgress, _def_nVal ) if(_def_pProgress&&_def_pProgress->IsSet())(_def_pProgress->Call((void*)(sal_IntPtr)_def_nVal));
46 :
47 : struct ChainMove { long nDX; long nDY; };
48 :
49 : static const ChainMove aImplMove[ 8 ] = {
50 : { 1L, 0L },
51 : { 0L, -1L },
52 : { -1L, 0L },
53 : { 0L, 1L },
54 : { 1L, -1L },
55 : { -1, -1L },
56 : { -1L, 1L },
57 : { 1L, 1L }
58 : };
59 :
60 : static const ChainMove aImplMoveInner[ 8 ] = {
61 : { 0L, 1L },
62 : { 1L, 0L },
63 : { 0L, -1L },
64 : { -1L, 0L },
65 : { 0L, 1L },
66 : { 1L, 0L },
67 : { 0L, -1L },
68 : { -1L, 0L }
69 : };
70 :
71 : static const ChainMove aImplMoveOuter[ 8 ] = {
72 : { 0L, -1L },
73 : { -1L, 0L },
74 : { 0L, 1L },
75 : { 1L, 0L },
76 : { -1L, 0L },
77 : { 0L, 1L },
78 : { 1L, 0L },
79 : { 0L, -1L }
80 : };
81 :
82 : struct ImplColorSet
83 : {
84 : BitmapColor maColor;
85 : sal_uInt16 mnIndex;
86 : bool mbSet;
87 : };
88 :
89 0 : extern "C" int SAL_CALL ImplColorSetCmpFnc( const void* p1, const void* p2 )
90 : {
91 0 : ImplColorSet* pSet1 = (ImplColorSet*) p1;
92 0 : ImplColorSet* pSet2 = (ImplColorSet*) p2;
93 : int nRet;
94 :
95 0 : if( pSet1->mbSet && pSet2->mbSet )
96 : {
97 0 : const sal_uInt8 cLum1 = pSet1->maColor.GetLuminance();
98 0 : const sal_uInt8 cLum2 = pSet2->maColor.GetLuminance();
99 0 : nRet = ( ( cLum1 > cLum2 ) ? -1 : ( ( cLum1 == cLum2 ) ? 0 : 1 ) );
100 : }
101 0 : else if( pSet1->mbSet )
102 0 : nRet = -1;
103 0 : else if( pSet2->mbSet )
104 0 : nRet = 1;
105 : else
106 0 : nRet = 0;
107 :
108 0 : return nRet;
109 : }
110 :
111 : class ImplPointArray
112 : {
113 : Point* mpArray;
114 : sal_uLong mnSize;
115 : sal_uLong mnRealSize;
116 :
117 : public:
118 :
119 : ImplPointArray();
120 : ~ImplPointArray();
121 :
122 : void ImplSetSize( sal_uLong nSize );
123 :
124 0 : sal_uLong ImplGetRealSize() const { return mnRealSize; }
125 0 : void ImplSetRealSize( sal_uLong nRealSize ) { mnRealSize = nRealSize; }
126 :
127 : inline Point& operator[]( sal_uLong nPos );
128 : inline const Point& operator[]( sal_uLong nPos ) const;
129 :
130 : void ImplCreatePoly( Polygon& rPoly ) const;
131 : };
132 :
133 0 : ImplPointArray::ImplPointArray() :
134 : mpArray ( NULL ),
135 : mnSize ( 0UL ),
136 0 : mnRealSize ( 0UL )
137 :
138 : {
139 0 : }
140 :
141 0 : ImplPointArray::~ImplPointArray()
142 : {
143 0 : if( mpArray )
144 0 : rtl_freeMemory( mpArray );
145 0 : }
146 :
147 0 : void ImplPointArray::ImplSetSize( sal_uLong nSize )
148 : {
149 0 : const sal_uLong nTotal = nSize * sizeof( Point );
150 :
151 0 : mnSize = nSize;
152 0 : mnRealSize = 0UL;
153 :
154 0 : if( mpArray )
155 0 : rtl_freeMemory( mpArray );
156 :
157 0 : mpArray = (Point*) rtl_allocateMemory( nTotal );
158 0 : memset( (HPBYTE) mpArray, 0, nTotal );
159 0 : }
160 :
161 0 : inline Point& ImplPointArray::operator[]( sal_uLong nPos )
162 : {
163 : DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" );
164 0 : return mpArray[ nPos ];
165 : }
166 :
167 0 : inline const Point& ImplPointArray::operator[]( sal_uLong nPos ) const
168 : {
169 : DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" );
170 0 : return mpArray[ nPos ];
171 : }
172 :
173 0 : void ImplPointArray::ImplCreatePoly( Polygon& rPoly ) const
174 : {
175 0 : rPoly = Polygon( sal::static_int_cast<sal_uInt16>(mnRealSize), mpArray );
176 0 : }
177 :
178 : class ImplVectMap
179 : {
180 : private:
181 :
182 : Scanline mpBuf;
183 : Scanline* mpScan;
184 : long mnWidth;
185 : long mnHeight;
186 :
187 : public:
188 :
189 : ImplVectMap( long nWidth, long nHeight );
190 : ~ImplVectMap();
191 :
192 0 : inline long Width() const { return mnWidth; }
193 0 : inline long Height() const { return mnHeight; }
194 :
195 : inline void Set( long nY, long nX, sal_uInt8 cVal );
196 : inline sal_uInt8 Get( long nY, long nX ) const;
197 :
198 : inline bool IsFree( long nY, long nX ) const;
199 : inline bool IsCont( long nY, long nX ) const;
200 : inline bool IsDone( long nY, long nX ) const;
201 :
202 : };
203 :
204 0 : ImplVectMap::ImplVectMap( long nWidth, long nHeight ) :
205 : mnWidth ( nWidth ),
206 0 : mnHeight( nHeight )
207 : {
208 0 : const long nWidthAl = ( nWidth >> 2L ) + 1L;
209 0 : const long nSize = nWidthAl * nHeight;
210 0 : Scanline pTmp = mpBuf = (Scanline) rtl_allocateMemory( nSize );
211 :
212 0 : memset( mpBuf, 0, nSize );
213 0 : mpScan = (Scanline*) rtl_allocateMemory( nHeight * sizeof( Scanline ) );
214 :
215 0 : for( long nY = 0L; nY < nHeight; pTmp += nWidthAl )
216 0 : mpScan[ nY++ ] = pTmp;
217 0 : }
218 :
219 0 : ImplVectMap::~ImplVectMap()
220 : {
221 0 : rtl_freeMemory( mpBuf );
222 0 : rtl_freeMemory( mpScan );
223 0 : }
224 :
225 0 : inline void ImplVectMap::Set( long nY, long nX, sal_uInt8 cVal )
226 : {
227 0 : const sal_uInt8 cShift = sal::static_int_cast<sal_uInt8>(6 - ( ( nX & 3 ) << 1 ));
228 0 : ( ( mpScan[ nY ][ nX >> 2 ] ) &= ~( 3 << cShift ) ) |= ( cVal << cShift );
229 0 : }
230 :
231 0 : inline sal_uInt8 ImplVectMap::Get( long nY, long nX ) const
232 : {
233 0 : return sal::static_int_cast<sal_uInt8>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 );
234 : }
235 :
236 0 : inline bool ImplVectMap::IsFree( long nY, long nX ) const
237 : {
238 0 : return( VECT_FREE_INDEX == Get( nY, nX ) );
239 : }
240 :
241 0 : inline bool ImplVectMap::IsCont( long nY, long nX ) const
242 : {
243 0 : return( VECT_CONT_INDEX == Get( nY, nX ) );
244 : }
245 :
246 0 : inline bool ImplVectMap::IsDone( long nY, long nX ) const
247 : {
248 0 : return( VECT_DONE_INDEX == Get( nY, nX ) );
249 : }
250 :
251 : class ImplChain
252 : {
253 : private:
254 :
255 : Polygon maPoly;
256 : Point maStartPt;
257 : sal_uLong mnArraySize;
258 : sal_uLong mnCount;
259 : long mnResize;
260 : sal_uInt8* mpCodes;
261 :
262 : void ImplGetSpace();
263 :
264 : void ImplPostProcess( const ImplPointArray& rArr );
265 :
266 : public:
267 :
268 : ImplChain( sal_uLong nInitCount = 1024UL, long nResize = -1L );
269 : ~ImplChain();
270 :
271 : void ImplBeginAdd( const Point& rStartPt );
272 : inline void ImplAdd( sal_uInt8 nCode );
273 : void ImplEndAdd( sal_uLong nTypeFlag );
274 :
275 0 : const Polygon& ImplGetPoly() const { return maPoly; }
276 : };
277 :
278 0 : ImplChain::ImplChain( sal_uLong nInitCount, long nResize ) :
279 : mnArraySize ( nInitCount ),
280 : mnCount ( 0UL ),
281 0 : mnResize ( nResize )
282 : {
283 : DBG_ASSERT( nInitCount && nResize, "ImplChain::ImplChain(): invalid parameters!" );
284 0 : mpCodes = new sal_uInt8[ mnArraySize ];
285 0 : }
286 :
287 0 : ImplChain::~ImplChain()
288 : {
289 0 : delete[] mpCodes;
290 0 : }
291 :
292 0 : void ImplChain::ImplGetSpace()
293 : {
294 0 : const sal_uLong nOldArraySize = mnArraySize;
295 : sal_uInt8* pNewCodes;
296 :
297 0 : mnArraySize = ( mnResize < 0L ) ? ( mnArraySize << 1UL ) : ( mnArraySize + (sal_uLong) mnResize );
298 0 : pNewCodes = new sal_uInt8[ mnArraySize ];
299 0 : memcpy( pNewCodes, mpCodes, nOldArraySize );
300 0 : delete[] mpCodes;
301 0 : mpCodes = pNewCodes;
302 0 : }
303 :
304 0 : void ImplChain::ImplBeginAdd( const Point& rStartPt )
305 : {
306 0 : maPoly = Polygon();
307 0 : maStartPt = rStartPt;
308 0 : mnCount = 0UL;
309 0 : }
310 :
311 0 : inline void ImplChain::ImplAdd( sal_uInt8 nCode )
312 : {
313 0 : if( mnCount == mnArraySize )
314 0 : ImplGetSpace();
315 :
316 0 : mpCodes[ mnCount++ ] = nCode;
317 0 : }
318 :
319 0 : void ImplChain::ImplEndAdd( sal_uLong nFlag )
320 : {
321 0 : if( mnCount )
322 : {
323 0 : ImplPointArray aArr;
324 :
325 0 : if( nFlag & VECT_POLY_INLINE_INNER )
326 : {
327 : long nFirstX, nFirstY;
328 : long nLastX, nLastY;
329 :
330 0 : nFirstX = nLastX = maStartPt.X();
331 0 : nFirstY = nLastY = maStartPt.Y();
332 0 : aArr.ImplSetSize( mnCount << 1 );
333 :
334 : sal_uInt16 i, nPolyPos;
335 0 : for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
336 : {
337 0 : const sal_uInt8 cMove = mpCodes[ i ];
338 0 : const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
339 0 : const ChainMove& rMove = aImplMove[ cMove ];
340 0 : const ChainMove& rMoveInner = aImplMoveInner[ cMove ];
341 : // Point& rPt = aArr[ nPolyPos ];
342 0 : bool bDone = true;
343 :
344 0 : nLastX += rMove.nDX;
345 0 : nLastY += rMove.nDY;
346 :
347 0 : if( cMove < 4 )
348 : {
349 0 : if( ( cMove == 0 && cNextMove == 3 ) ||
350 0 : ( cMove == 3 && cNextMove == 2 ) ||
351 0 : ( cMove == 2 && cNextMove == 1 ) ||
352 0 : ( cMove == 1 && cNextMove == 0 ) )
353 : {
354 : }
355 0 : else if( cMove == 2 && cNextMove == 3 )
356 : {
357 0 : aArr[ nPolyPos ].X() = nLastX;
358 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
359 :
360 0 : aArr[ nPolyPos ].X() = nLastX - 1;
361 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
362 :
363 0 : aArr[ nPolyPos ].X() = nLastX - 1;
364 0 : aArr[ nPolyPos++ ].Y() = nLastY;
365 : }
366 0 : else if( cMove == 3 && cNextMove == 0 )
367 : {
368 0 : aArr[ nPolyPos ].X() = nLastX - 1;
369 0 : aArr[ nPolyPos++ ].Y() = nLastY;
370 :
371 0 : aArr[ nPolyPos ].X() = nLastX - 1;
372 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
373 :
374 0 : aArr[ nPolyPos ].X() = nLastX;
375 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
376 : }
377 0 : else if( cMove == 0 && cNextMove == 1 )
378 : {
379 0 : aArr[ nPolyPos ].X() = nLastX;
380 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
381 :
382 0 : aArr[ nPolyPos ].X() = nLastX + 1;
383 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
384 :
385 0 : aArr[ nPolyPos ].X() = nLastX + 1;
386 0 : aArr[ nPolyPos++ ].Y() = nLastY;
387 : }
388 0 : else if( cMove == 1 && cNextMove == 2 )
389 : {
390 0 : aArr[ nPolyPos ].X() = nLastX + 1;
391 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
392 :
393 0 : aArr[ nPolyPos ].X() = nLastX + 1;
394 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
395 :
396 0 : aArr[ nPolyPos ].X() = nLastX;
397 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
398 : }
399 : else
400 0 : bDone = false;
401 : }
402 0 : else if( cMove == 7 && cNextMove == 0 )
403 : {
404 0 : aArr[ nPolyPos ].X() = nLastX - 1;
405 0 : aArr[ nPolyPos++ ].Y() = nLastY;
406 :
407 0 : aArr[ nPolyPos ].X() = nLastX;
408 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
409 : }
410 0 : else if( cMove == 4 && cNextMove == 1 )
411 : {
412 0 : aArr[ nPolyPos ].X() = nLastX;
413 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
414 :
415 0 : aArr[ nPolyPos ].X() = nLastX + 1;
416 0 : aArr[ nPolyPos++ ].Y() = nLastY;
417 : }
418 : else
419 0 : bDone = false;
420 :
421 0 : if( !bDone )
422 : {
423 0 : aArr[ nPolyPos ].X() = nLastX + rMoveInner.nDX;
424 0 : aArr[ nPolyPos++ ].Y() = nLastY + rMoveInner.nDY;
425 : }
426 : }
427 :
428 0 : aArr[ nPolyPos ].X() = nFirstX + 1L;
429 0 : aArr[ nPolyPos++ ].Y() = nFirstY + 1L;
430 0 : aArr.ImplSetRealSize( nPolyPos );
431 : }
432 0 : else if( nFlag & VECT_POLY_INLINE_OUTER )
433 : {
434 : long nFirstX, nFirstY;
435 : long nLastX, nLastY;
436 :
437 0 : nFirstX = nLastX = maStartPt.X();
438 0 : nFirstY = nLastY = maStartPt.Y();
439 0 : aArr.ImplSetSize( mnCount << 1 );
440 :
441 : sal_uInt16 i, nPolyPos;
442 0 : for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
443 : {
444 0 : const sal_uInt8 cMove = mpCodes[ i ];
445 0 : const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
446 0 : const ChainMove& rMove = aImplMove[ cMove ];
447 0 : const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ];
448 : // Point& rPt = aArr[ nPolyPos ];
449 0 : bool bDone = true;
450 :
451 0 : nLastX += rMove.nDX;
452 0 : nLastY += rMove.nDY;
453 :
454 0 : if( cMove < 4 )
455 : {
456 0 : if( ( cMove == 0 && cNextMove == 1 ) ||
457 0 : ( cMove == 1 && cNextMove == 2 ) ||
458 0 : ( cMove == 2 && cNextMove == 3 ) ||
459 0 : ( cMove == 3 && cNextMove == 0 ) )
460 : {
461 : }
462 0 : else if( cMove == 0 && cNextMove == 3 )
463 : {
464 0 : aArr[ nPolyPos ].X() = nLastX;
465 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
466 :
467 0 : aArr[ nPolyPos ].X() = nLastX + 1;
468 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
469 :
470 0 : aArr[ nPolyPos ].X() = nLastX + 1;
471 0 : aArr[ nPolyPos++ ].Y() = nLastY;
472 : }
473 0 : else if( cMove == 3 && cNextMove == 2 )
474 : {
475 0 : aArr[ nPolyPos ].X() = nLastX + 1;
476 0 : aArr[ nPolyPos++ ].Y() = nLastY;
477 :
478 0 : aArr[ nPolyPos ].X() = nLastX + 1;
479 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
480 :
481 0 : aArr[ nPolyPos ].X() = nLastX;
482 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
483 : }
484 0 : else if( cMove == 2 && cNextMove == 1 )
485 : {
486 0 : aArr[ nPolyPos ].X() = nLastX;
487 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
488 :
489 0 : aArr[ nPolyPos ].X() = nLastX - 1;
490 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
491 :
492 0 : aArr[ nPolyPos ].X() = nLastX - 1;
493 0 : aArr[ nPolyPos++ ].Y() = nLastY;
494 : }
495 0 : else if( cMove == 1 && cNextMove == 0 )
496 : {
497 0 : aArr[ nPolyPos ].X() = nLastX - 1;
498 0 : aArr[ nPolyPos++ ].Y() = nLastY;
499 :
500 0 : aArr[ nPolyPos ].X() = nLastX - 1;
501 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
502 :
503 0 : aArr[ nPolyPos ].X() = nLastX;
504 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
505 : }
506 : else
507 0 : bDone = false;
508 : }
509 0 : else if( cMove == 7 && cNextMove == 3 )
510 : {
511 0 : aArr[ nPolyPos ].X() = nLastX;
512 0 : aArr[ nPolyPos++ ].Y() = nLastY - 1;
513 :
514 0 : aArr[ nPolyPos ].X() = nLastX + 1;
515 0 : aArr[ nPolyPos++ ].Y() = nLastY;
516 : }
517 0 : else if( cMove == 6 && cNextMove == 2 )
518 : {
519 0 : aArr[ nPolyPos ].X() = nLastX + 1;
520 0 : aArr[ nPolyPos++ ].Y() = nLastY;
521 :
522 0 : aArr[ nPolyPos ].X() = nLastX;
523 0 : aArr[ nPolyPos++ ].Y() = nLastY + 1;
524 : }
525 : else
526 0 : bDone = false;
527 :
528 0 : if( !bDone )
529 : {
530 0 : aArr[ nPolyPos ].X() = nLastX + rMoveOuter.nDX;
531 0 : aArr[ nPolyPos++ ].Y() = nLastY + rMoveOuter.nDY;
532 : }
533 : }
534 :
535 0 : aArr[ nPolyPos ].X() = nFirstX - 1L;
536 0 : aArr[ nPolyPos++ ].Y() = nFirstY - 1L;
537 0 : aArr.ImplSetRealSize( nPolyPos );
538 : }
539 : else
540 : {
541 0 : long nLastX = maStartPt.X(), nLastY = maStartPt.Y();
542 :
543 0 : aArr.ImplSetSize( mnCount + 1 );
544 0 : aArr[ 0 ] = Point( nLastX, nLastY );
545 :
546 0 : for( sal_uLong i = 0; i < mnCount; )
547 : {
548 0 : const ChainMove& rMove = aImplMove[ mpCodes[ i ] ];
549 0 : aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY );
550 : }
551 :
552 0 : aArr.ImplSetRealSize( mnCount + 1 );
553 : }
554 :
555 0 : ImplPostProcess( aArr );
556 : }
557 : else
558 0 : maPoly.SetSize( 0 );
559 0 : }
560 :
561 0 : void ImplChain::ImplPostProcess( const ImplPointArray& rArr )
562 : {
563 0 : ImplPointArray aNewArr1;
564 0 : ImplPointArray aNewArr2;
565 : Point* pLast;
566 : Point* pLeast;
567 : sal_uLong nNewPos;
568 0 : sal_uLong nCount = rArr.ImplGetRealSize();
569 : sal_uLong n;
570 :
571 : // pass 1
572 0 : aNewArr1.ImplSetSize( nCount );
573 0 : pLast = &( aNewArr1[ 0 ] );
574 0 : pLast->X() = BACK_MAP( rArr[ 0 ].X() );
575 0 : pLast->Y() = BACK_MAP( rArr[ 0 ].Y() );
576 :
577 0 : for( n = nNewPos = 1; n < nCount; )
578 : {
579 0 : const Point& rPt = rArr[ n++ ];
580 0 : const long nX = BACK_MAP( rPt.X() );
581 0 : const long nY = BACK_MAP( rPt.Y() );
582 :
583 0 : if( nX != pLast->X() || nY != pLast->Y() )
584 : {
585 0 : pLast = pLeast = &( aNewArr1[ nNewPos++ ] );
586 0 : pLeast->X() = nX;
587 0 : pLeast->Y() = nY;
588 : }
589 : }
590 :
591 0 : aNewArr1.ImplSetRealSize( nCount = nNewPos );
592 :
593 : // pass 2
594 0 : aNewArr2.ImplSetSize( nCount );
595 0 : pLast = &( aNewArr2[ 0 ] );
596 0 : *pLast = aNewArr1[ 0 ];
597 :
598 0 : for( n = nNewPos = 1; n < nCount; )
599 : {
600 0 : pLeast = &( aNewArr1[ n++ ] );
601 :
602 0 : if( pLeast->X() == pLast->X() )
603 : {
604 0 : while( n < nCount && aNewArr1[ n ].X() == pLast->X() )
605 0 : pLeast = &( aNewArr1[ n++ ] );
606 : }
607 0 : else if( pLeast->Y() == pLast->Y() )
608 : {
609 0 : while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() )
610 0 : pLeast = &( aNewArr1[ n++ ] );
611 : }
612 :
613 0 : aNewArr2[ nNewPos++ ] = *( pLast = pLeast );
614 : }
615 :
616 0 : aNewArr2.ImplSetRealSize( nNewPos );
617 0 : aNewArr2.ImplCreatePoly( maPoly );
618 0 : }
619 :
620 0 : ImplVectorizer::ImplVectorizer()
621 : {
622 0 : }
623 :
624 0 : ImplVectorizer::~ImplVectorizer()
625 : {
626 0 : }
627 :
628 0 : bool ImplVectorizer::ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf,
629 : sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
630 : {
631 0 : bool bRet = false;
632 :
633 0 : VECT_PROGRESS( pProgress, 0 );
634 :
635 0 : boost::scoped_ptr<Bitmap> pBmp(new Bitmap( rColorBmp ));
636 0 : BitmapReadAccess* pRAcc = pBmp->AcquireReadAccess();
637 :
638 0 : if( pRAcc )
639 : {
640 0 : PolyPolygon aPolyPoly;
641 0 : double fPercent = 0.0;
642 0 : double fPercentStep_2 = 0.0;
643 0 : const long nWidth = pRAcc->Width();
644 0 : const long nHeight = pRAcc->Height();
645 0 : const sal_uInt16 nColorCount = pRAcc->GetPaletteEntryCount();
646 : sal_uInt16 n;
647 0 : ImplColorSet* pColorSet = (ImplColorSet*) new sal_uInt8[ 256 * sizeof( ImplColorSet ) ];
648 :
649 0 : memset( pColorSet, 0, 256 * sizeof( ImplColorSet ) );
650 0 : rMtf.Clear();
651 :
652 : // get used palette colors and sort them from light to dark colors
653 0 : for( n = 0; n < nColorCount; n++ )
654 : {
655 0 : pColorSet[ n ].mnIndex = n;
656 0 : pColorSet[ n ].maColor = pRAcc->GetPaletteColor( n );
657 : }
658 :
659 0 : for( long nY = 0L; nY < nHeight; nY++ )
660 0 : for( long nX = 0L; nX < nWidth; nX++ )
661 0 : pColorSet[ pRAcc->GetPixel( nY, nX ).GetIndex() ].mbSet = true;
662 :
663 0 : qsort( pColorSet, 256, sizeof( ImplColorSet ), ImplColorSetCmpFnc );
664 :
665 0 : for( n = 0; n < 256; n++ )
666 0 : if( !pColorSet[ n ].mbSet )
667 0 : break;
668 :
669 0 : if( n )
670 0 : fPercentStep_2 = 45.0 / n;
671 :
672 0 : VECT_PROGRESS( pProgress, FRound( fPercent += 10.0 ) );
673 :
674 0 : for( sal_uInt16 i = 0; i < n; i++ )
675 : {
676 0 : const BitmapColor aBmpCol( pRAcc->GetPaletteColor( pColorSet[ i ].mnIndex ) );
677 0 : const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() );
678 : // const sal_uInt8 cLum = aFindColor.GetLuminance();
679 0 : boost::scoped_ptr<ImplVectMap> pMap(ImplExpand( pRAcc, aFindColor ));
680 :
681 0 : VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) );
682 :
683 0 : if( pMap )
684 : {
685 0 : aPolyPoly.Clear();
686 0 : ImplCalculate( pMap.get(), aPolyPoly, cReduce, nFlags );
687 0 : pMap.reset();
688 :
689 0 : if( aPolyPoly.Count() )
690 : {
691 0 : ImplLimitPolyPoly( aPolyPoly );
692 :
693 0 : if( nFlags & BMP_VECTORIZE_REDUCE_EDGES )
694 0 : aPolyPoly.Optimize( POLY_OPTIMIZE_EDGES );
695 :
696 0 : if( aPolyPoly.Count() )
697 : {
698 0 : rMtf.AddAction( new MetaLineColorAction( aFindColor, true ) );
699 0 : rMtf.AddAction( new MetaFillColorAction( aFindColor, true ) );
700 0 : rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
701 : }
702 : }
703 : }
704 :
705 0 : VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) );
706 0 : }
707 :
708 0 : delete[] (sal_uInt8*) pColorSet;
709 :
710 0 : if( rMtf.GetActionSize() )
711 : {
712 0 : MapMode aMap( MAP_100TH_MM );
713 0 : VirtualDevice aVDev;
714 0 : const Size aLogSize1( aVDev.PixelToLogic( Size( 1, 1 ), aMap ) );
715 :
716 0 : rMtf.SetPrefMapMode( aMap );
717 0 : rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
718 0 : rMtf.Move( 1, 1 );
719 0 : rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() );
720 0 : bRet = true;
721 0 : }
722 : }
723 :
724 0 : pBmp->ReleaseAccess( pRAcc );
725 0 : pBmp.reset();
726 0 : VECT_PROGRESS( pProgress, 100 );
727 :
728 0 : return bRet;
729 : }
730 :
731 0 : bool ImplVectorizer::ImplVectorize( const Bitmap& rMonoBmp,
732 : PolyPolygon& rPolyPoly,
733 : sal_uLong nFlags, const Link* pProgress )
734 : {
735 0 : boost::scoped_ptr<Bitmap> pBmp(new Bitmap( rMonoBmp ));
736 : BitmapReadAccess* pRAcc;
737 0 : bool bRet = false;
738 :
739 0 : VECT_PROGRESS( pProgress, 10 );
740 :
741 0 : if( pBmp->GetBitCount() > 1 )
742 0 : pBmp->Convert( BMP_CONVERSION_1BIT_THRESHOLD );
743 :
744 0 : VECT_PROGRESS( pProgress, 30 );
745 :
746 0 : pRAcc = pBmp->AcquireReadAccess();
747 0 : boost::scoped_ptr<ImplVectMap> pMap(ImplExpand( pRAcc, COL_BLACK ));
748 0 : pBmp->ReleaseAccess( pRAcc );
749 0 : pBmp.reset();
750 :
751 0 : VECT_PROGRESS( pProgress, 60 );
752 :
753 0 : if( pMap )
754 : {
755 0 : rPolyPoly.Clear();
756 0 : ImplCalculate( pMap.get(), rPolyPoly, 0, nFlags );
757 0 : pMap.reset();
758 0 : ImplLimitPolyPoly( rPolyPoly );
759 :
760 0 : if( nFlags & BMP_VECTORIZE_REDUCE_EDGES )
761 0 : rPolyPoly.Optimize( POLY_OPTIMIZE_EDGES );
762 :
763 : // #i14895#:setting the correct direction for polygons
764 : // that represent holes and non-holes; non-hole polygons
765 : // need to have a right orientation, holes need to have a
766 : // left orientation in order to be treated correctly by
767 : // several external tools like Flash viewers
768 0 : sal_Int32 nFirstPoly = -1;
769 0 : sal_uInt16 nCurPoly( 0 ), nCount( rPolyPoly.Count() );
770 :
771 0 : for( ; nCurPoly < nCount; ++nCurPoly )
772 : {
773 0 : const Polygon& rPoly = rPolyPoly.GetObject( nCurPoly );
774 0 : const sal_uInt16 nSize( rPoly.GetSize() );
775 0 : sal_uInt16 nDepth( 0 ), i( 0 );
776 0 : const bool bRight( rPoly.IsRightOrientated() );
777 :
778 0 : for( ; i < nCount; ++i )
779 0 : if( ( i != nCurPoly ) && rPolyPoly.GetObject( i ).IsInside( rPoly[ 0 ] ) )
780 0 : ++nDepth;
781 :
782 0 : const bool bHole( ( nDepth & 0x0001 ) == 1 );
783 :
784 0 : if( nSize && ( ( !bRight && !bHole ) || ( bRight && bHole ) ) )
785 : {
786 0 : Polygon aNewPoly( nSize );
787 0 : sal_uInt16 nPrim( 0 ), nSec( nSize - 1 );
788 :
789 0 : if( rPoly.HasFlags() )
790 : {
791 0 : while( nPrim < nSize )
792 : {
793 0 : aNewPoly.SetPoint( rPoly.GetPoint( nSec ), nPrim );
794 0 : aNewPoly.SetFlags( nPrim++, rPoly.GetFlags( nSec-- ) );
795 : }
796 : }
797 : else
798 0 : while( nPrim < nSize )
799 0 : aNewPoly.SetPoint( rPoly.GetPoint( nSec-- ), nPrim++ );
800 :
801 0 : rPolyPoly.Replace( aNewPoly, nCurPoly );
802 : }
803 :
804 0 : if( ( 0 == nDepth ) && ( -1 == nFirstPoly ) )
805 0 : nFirstPoly = nCurPoly;
806 : }
807 :
808 : // put outmost polygon to the front
809 0 : if( nFirstPoly > 0 )
810 : {
811 0 : const Polygon aFirst( rPolyPoly.GetObject( static_cast< sal_uInt16 >( nFirstPoly ) ) );
812 :
813 0 : rPolyPoly.Remove( static_cast< sal_uInt16 >( nFirstPoly ) );
814 0 : rPolyPoly.Insert( aFirst, 0 );
815 : }
816 :
817 0 : bRet = true;
818 : }
819 :
820 0 : VECT_PROGRESS( pProgress, 100 );
821 :
822 0 : return bRet;
823 : }
824 :
825 0 : void ImplVectorizer::ImplLimitPolyPoly( PolyPolygon& rPolyPoly )
826 : {
827 0 : if( rPolyPoly.Count() > VECT_POLY_MAX )
828 : {
829 0 : PolyPolygon aNewPolyPoly;
830 0 : long nReduce = 0;
831 : sal_uInt16 nNewCount;
832 :
833 0 : do
834 : {
835 0 : aNewPolyPoly.Clear();
836 0 : nReduce++;
837 :
838 0 : for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
839 : {
840 0 : const Rectangle aBound( rPolyPoly[ i ].GetBoundRect() );
841 :
842 0 : if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce )
843 : {
844 0 : if( rPolyPoly[ i ].GetSize() )
845 0 : aNewPolyPoly.Insert( rPolyPoly[ i ] );
846 : }
847 : }
848 :
849 0 : nNewCount = aNewPolyPoly.Count();
850 : }
851 : while( nNewCount > VECT_POLY_MAX );
852 :
853 0 : rPolyPoly = aNewPolyPoly;
854 : }
855 0 : }
856 :
857 0 : ImplVectMap* ImplVectorizer::ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor )
858 : {
859 0 : ImplVectMap* pMap = NULL;
860 :
861 0 : if( pRAcc && pRAcc->Width() && pRAcc->Height() )
862 : {
863 0 : const long nOldWidth = pRAcc->Width();
864 0 : const long nOldHeight = pRAcc->Height();
865 0 : const long nNewWidth = ( nOldWidth << 2L ) + 4L;
866 0 : const long nNewHeight = ( nOldHeight << 2L ) + 4L;
867 0 : const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) );
868 0 : boost::scoped_array<long> pMapIn(new long[ std::max( nOldWidth, nOldHeight ) ]);
869 0 : boost::scoped_array<long> pMapOut(new long[ std::max( nOldWidth, nOldHeight ) ]);
870 : long nX, nY, nTmpX, nTmpY;
871 :
872 0 : pMap = new ImplVectMap( nNewWidth, nNewHeight );
873 :
874 0 : for( nX = 0L; nX < nOldWidth; nX++ )
875 0 : VECT_MAP( pMapIn, pMapOut, nX );
876 :
877 0 : for( nY = 0L, nTmpY = 5L; nY < nOldHeight; nY++, nTmpY += 4L )
878 : {
879 0 : for( nX = 0L; nX < nOldWidth; )
880 : {
881 0 : if( pRAcc->GetPixel( nY, nX ) == aTest )
882 : {
883 0 : nTmpX = pMapIn[ nX++ ];
884 0 : nTmpY -= 3L;
885 :
886 0 : pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
887 0 : pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
888 0 : pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
889 0 : pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
890 :
891 0 : while( nX < nOldWidth && pRAcc->GetPixel( nY, nX ) == aTest )
892 0 : nX++;
893 :
894 0 : nTmpX = pMapOut[ nX - 1L ];
895 0 : nTmpY -= 3L;
896 :
897 0 : pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
898 0 : pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
899 0 : pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
900 0 : pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
901 : }
902 : else
903 0 : nX++;
904 : }
905 : }
906 :
907 0 : for( nY = 0L; nY < nOldHeight; nY++ )
908 0 : VECT_MAP( pMapIn, pMapOut, nY );
909 :
910 0 : for( nX = 0L, nTmpX = 5L; nX < nOldWidth; nX++, nTmpX += 4L )
911 : {
912 0 : for( nY = 0L; nY < nOldHeight; )
913 : {
914 0 : if( pRAcc->GetPixel( nY, nX ) == aTest )
915 : {
916 0 : nTmpX -= 3L;
917 0 : nTmpY = pMapIn[ nY++ ];
918 :
919 0 : pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
920 0 : pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
921 0 : pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
922 0 : pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
923 :
924 0 : while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest )
925 0 : nY++;
926 :
927 0 : nTmpX -= 3L;
928 0 : nTmpY = pMapOut[ nY - 1L ];
929 :
930 0 : pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
931 0 : pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
932 0 : pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
933 0 : pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
934 : }
935 : else
936 0 : nY++;
937 : }
938 0 : }
939 : }
940 :
941 0 : return pMap;
942 : }
943 :
944 0 : void ImplVectorizer::ImplCalculate( ImplVectMap* pMap, PolyPolygon& rPolyPoly, sal_uInt8 cReduce, sal_uLong nFlags )
945 : {
946 0 : const long nWidth = pMap->Width(), nHeight= pMap->Height();
947 :
948 0 : for( long nY = 0L; nY < nHeight; nY++ )
949 : {
950 0 : long nX = 0L;
951 0 : bool bInner = true;
952 :
953 0 : while( nX < nWidth )
954 : {
955 : // skip free
956 0 : while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) )
957 0 : nX++;
958 :
959 0 : if( nX == nWidth )
960 0 : break;
961 :
962 0 : if( pMap->IsCont( nY, nX ) )
963 : {
964 : // new contour
965 0 : ImplChain aChain;
966 0 : const Point aStartPt( nX++, nY );
967 :
968 : // get chain code
969 0 : aChain.ImplBeginAdd( aStartPt );
970 0 : ImplGetChain( pMap, aStartPt, aChain );
971 :
972 0 : if( nFlags & BMP_VECTORIZE_INNER )
973 0 : aChain.ImplEndAdd( bInner ? VECT_POLY_INLINE_INNER : VECT_POLY_INLINE_OUTER );
974 : else
975 0 : aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER );
976 :
977 0 : const Polygon& rPoly = aChain.ImplGetPoly();
978 :
979 0 : if( rPoly.GetSize() > 2 )
980 : {
981 0 : if( cReduce )
982 : {
983 0 : const Rectangle aBound( rPoly.GetBoundRect() );
984 :
985 0 : if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
986 0 : rPolyPoly.Insert( rPoly );
987 : }
988 : else
989 0 : rPolyPoly.Insert( rPoly );
990 : }
991 :
992 : // skip rest of detected contour
993 0 : while( pMap->IsCont( nY, nX ) )
994 0 : nX++;
995 : }
996 : else
997 : {
998 : // process done segment
999 0 : const long nStartSegX = nX++;
1000 :
1001 0 : while( pMap->IsDone( nY, nX ) )
1002 0 : nX++;
1003 :
1004 0 : if( ( ( nX - nStartSegX ) == 1L ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1L ) ) )
1005 0 : bInner = !bInner;
1006 : }
1007 : }
1008 : }
1009 0 : }
1010 :
1011 0 : bool ImplVectorizer::ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain )
1012 : {
1013 0 : long nActX = rStartPt.X();
1014 0 : long nActY = rStartPt.Y();
1015 : long nTryX;
1016 : long nTryY;
1017 : sal_uLong nFound;
1018 0 : sal_uLong nLastDir = 0UL;
1019 : sal_uLong nDir;
1020 :
1021 0 : do
1022 : {
1023 0 : nFound = 0UL;
1024 :
1025 : // first try last direction
1026 0 : nTryX = nActX + aImplMove[ nLastDir ].nDX;
1027 0 : nTryY = nActY + aImplMove[ nLastDir ].nDY;
1028 :
1029 0 : if( pMap->IsCont( nTryY, nTryX ) )
1030 : {
1031 0 : rChain.ImplAdd( (sal_uInt8) nLastDir );
1032 0 : pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX );
1033 0 : nFound = 1UL;
1034 : }
1035 : else
1036 : {
1037 : // try other directions
1038 0 : for( nDir = 0UL; nDir < 8UL; nDir++ )
1039 : {
1040 : // we already tried nLastDir
1041 0 : if( nDir != nLastDir )
1042 : {
1043 0 : nTryX = nActX + aImplMove[ nDir ].nDX;
1044 0 : nTryY = nActY + aImplMove[ nDir ].nDY;
1045 :
1046 0 : if( pMap->IsCont( nTryY, nTryX ) )
1047 : {
1048 0 : rChain.ImplAdd( (sal_uInt8) nDir );
1049 0 : pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX );
1050 0 : nFound = 1UL;
1051 0 : nLastDir = nDir;
1052 0 : break;
1053 : }
1054 : }
1055 : }
1056 : }
1057 : }
1058 : while( nFound );
1059 :
1060 0 : return true;
1061 : }
1062 :
1063 0 : bool ImplVectorizer::ImplIsUp( ImplVectMap* pMap, long nY, long nX ) const
1064 : {
1065 0 : if( pMap->IsDone( nY - 1L, nX ) )
1066 0 : return true;
1067 0 : else if( pMap->IsDone( nY + 1L, nX ) )
1068 0 : return false;
1069 0 : else if( pMap->IsDone( nY - 1L, nX - 1L ) || pMap->IsDone( nY - 1L, nX + 1L ) )
1070 0 : return true;
1071 : else
1072 0 : return false;
1073 : }
1074 :
1075 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|