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