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 : #define POLY_CLIP_INT 0
21 : #define POLY_CLIP_UNION 1
22 : #define POLY_CLIP_DIFF 2
23 : #define POLY_CLIP_XOR 3
24 :
25 : #include <rtl/math.hxx>
26 : #include <sal/log.hxx>
27 : #include <osl/diagnose.h>
28 : #include <poly.h>
29 : #include <tools/poly.hxx>
30 : #include <tools/debug.hxx>
31 : #include <tools/stream.hxx>
32 : #include <tools/vcompat.hxx>
33 : #include <tools/gen.hxx>
34 : #include <basegfx/polygon/b2dpolypolygon.hxx>
35 : #include <basegfx/polygon/b2dpolygon.hxx>
36 : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
37 :
38 220624 : ImplPolyPolygon::ImplPolyPolygon( sal_uInt16 nInitSize )
39 : {
40 220624 : mnRefCount = 1;
41 220624 : mnCount = nInitSize;
42 220624 : mnSize = nInitSize;
43 220624 : mnResize = 16;
44 220624 : mpPolyAry = new SVPPOLYGON[ nInitSize ];
45 220624 : }
46 :
47 235267 : ImplPolyPolygon::ImplPolyPolygon( const ImplPolyPolygon& rImplPolyPoly )
48 : {
49 235267 : mnRefCount = 1;
50 235267 : mnCount = rImplPolyPoly.mnCount;
51 235267 : mnSize = rImplPolyPoly.mnSize;
52 235267 : mnResize = rImplPolyPoly.mnResize;
53 :
54 235267 : if ( rImplPolyPoly.mpPolyAry )
55 : {
56 233347 : mpPolyAry = new SVPPOLYGON[mnSize];
57 469450 : for ( sal_uInt16 i = 0; i < mnCount; i++ )
58 236103 : mpPolyAry[i] = new Polygon( *rImplPolyPoly.mpPolyAry[i] );
59 : }
60 : else
61 1920 : mpPolyAry = NULL;
62 235267 : }
63 :
64 782637 : ImplPolyPolygon::~ImplPolyPolygon()
65 : {
66 782637 : if ( mpPolyAry )
67 : {
68 1548234 : for ( sal_uInt16 i = 0; i < mnCount; i++ )
69 787178 : delete mpPolyAry[i];
70 761056 : delete[] mpPolyAry;
71 : }
72 782637 : }
73 :
74 : namespace tools {
75 :
76 322863 : PolyPolygon::PolyPolygon( sal_uInt16 nInitSize, sal_uInt16 nResize )
77 : {
78 322863 : if ( nInitSize > MAX_POLYGONS )
79 0 : nInitSize = MAX_POLYGONS;
80 322863 : else if ( !nInitSize )
81 0 : nInitSize = 1;
82 322863 : if ( nResize > MAX_POLYGONS )
83 0 : nResize = MAX_POLYGONS;
84 322863 : else if ( !nResize )
85 0 : nResize = 1;
86 322863 : mpImplPolyPolygon = new ImplPolyPolygon( nInitSize, nResize );
87 322863 : }
88 :
89 167534 : PolyPolygon::PolyPolygon( const Polygon& rPoly )
90 : {
91 167534 : if ( rPoly.GetSize() )
92 : {
93 167534 : mpImplPolyPolygon = new ImplPolyPolygon( 1 );
94 167534 : mpImplPolyPolygon->mpPolyAry[0] = new Polygon( rPoly );
95 : }
96 : else
97 0 : mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
98 167534 : }
99 :
100 450117 : PolyPolygon::PolyPolygon( const tools::PolyPolygon& rPolyPoly )
101 : {
102 : DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
103 :
104 450117 : mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
105 450117 : mpImplPolyPolygon->mnRefCount++;
106 450117 : }
107 :
108 996800 : PolyPolygon::~PolyPolygon()
109 : {
110 996800 : if ( mpImplPolyPolygon->mnRefCount > 1 )
111 222891 : mpImplPolyPolygon->mnRefCount--;
112 : else
113 773909 : delete mpImplPolyPolygon;
114 996800 : }
115 :
116 320352 : void PolyPolygon::Insert( const Polygon& rPoly, sal_uInt16 nPos )
117 : {
118 320352 : if ( mpImplPolyPolygon->mnCount >= MAX_POLYGONS )
119 320352 : return;
120 :
121 320352 : if ( mpImplPolyPolygon->mnRefCount > 1 )
122 : {
123 0 : mpImplPolyPolygon->mnRefCount--;
124 0 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
125 : }
126 :
127 320352 : if ( nPos > mpImplPolyPolygon->mnCount )
128 320331 : nPos = mpImplPolyPolygon->mnCount;
129 :
130 320352 : if ( !mpImplPolyPolygon->mpPolyAry )
131 307104 : mpImplPolyPolygon->mpPolyAry = new SVPPOLYGON[mpImplPolyPolygon->mnSize];
132 13248 : else if ( mpImplPolyPolygon->mnCount == mpImplPolyPolygon->mnSize )
133 : {
134 68 : sal_uInt16 nOldSize = mpImplPolyPolygon->mnSize;
135 68 : sal_uInt16 nNewSize = nOldSize + mpImplPolyPolygon->mnResize;
136 : SVPPOLYGON* pNewAry;
137 :
138 68 : if ( nNewSize >= MAX_POLYGONS )
139 0 : nNewSize = MAX_POLYGONS;
140 68 : pNewAry = new SVPPOLYGON[nNewSize];
141 68 : memcpy( pNewAry, mpImplPolyPolygon->mpPolyAry, nPos*sizeof(SVPPOLYGON) );
142 136 : memcpy( pNewAry+nPos+1, mpImplPolyPolygon->mpPolyAry+nPos,
143 204 : (nOldSize-nPos)*sizeof(SVPPOLYGON) );
144 68 : delete[] mpImplPolyPolygon->mpPolyAry;
145 68 : mpImplPolyPolygon->mpPolyAry = pNewAry;
146 68 : mpImplPolyPolygon->mnSize = nNewSize;
147 : }
148 13180 : else if ( nPos < mpImplPolyPolygon->mnCount )
149 : {
150 0 : memmove( mpImplPolyPolygon->mpPolyAry+nPos+1,
151 : mpImplPolyPolygon->mpPolyAry+nPos,
152 0 : (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
153 : }
154 :
155 320352 : mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
156 320352 : mpImplPolyPolygon->mnCount++;
157 : }
158 :
159 0 : void PolyPolygon::Remove( sal_uInt16 nPos )
160 : {
161 : assert(nPos < Count() && "PolyPolygon::Remove(): nPos >= nSize");
162 :
163 0 : if ( mpImplPolyPolygon->mnRefCount > 1 )
164 : {
165 0 : mpImplPolyPolygon->mnRefCount--;
166 0 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
167 : }
168 :
169 0 : delete mpImplPolyPolygon->mpPolyAry[nPos];
170 0 : mpImplPolyPolygon->mnCount--;
171 0 : memmove( mpImplPolyPolygon->mpPolyAry+nPos,
172 0 : mpImplPolyPolygon->mpPolyAry+nPos+1,
173 0 : (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
174 0 : }
175 :
176 3 : void PolyPolygon::Replace( const Polygon& rPoly, sal_uInt16 nPos )
177 : {
178 : assert(nPos < Count() && "PolyPolygon::Replace(): nPos >= nSize");
179 :
180 3 : if ( mpImplPolyPolygon->mnRefCount > 1 )
181 : {
182 0 : mpImplPolyPolygon->mnRefCount--;
183 0 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
184 : }
185 :
186 3 : delete mpImplPolyPolygon->mpPolyAry[nPos];
187 3 : mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
188 3 : }
189 :
190 622173 : const Polygon& PolyPolygon::GetObject( sal_uInt16 nPos ) const
191 : {
192 : assert(nPos < Count() && "PolyPolygon::GetObject(): nPos >= nSize");
193 :
194 622173 : return *(mpImplPolyPolygon->mpPolyAry[nPos]);
195 : }
196 :
197 158957 : bool PolyPolygon::IsRect() const
198 : {
199 158957 : bool bIsRect = false;
200 158957 : if ( Count() == 1 )
201 158867 : bIsRect = mpImplPolyPolygon->mpPolyAry[ 0 ]->IsRect();
202 158957 : return bIsRect;
203 : }
204 :
205 239 : void PolyPolygon::Clear()
206 : {
207 239 : if ( mpImplPolyPolygon->mnRefCount > 1 )
208 : {
209 22 : mpImplPolyPolygon->mnRefCount--;
210 : mpImplPolyPolygon = new ImplPolyPolygon( mpImplPolyPolygon->mnResize,
211 22 : mpImplPolyPolygon->mnResize );
212 : }
213 : else
214 : {
215 217 : if ( mpImplPolyPolygon->mpPolyAry )
216 : {
217 38 : for ( sal_uInt16 i = 0; i < mpImplPolyPolygon->mnCount; i++ )
218 19 : delete mpImplPolyPolygon->mpPolyAry[i];
219 19 : delete[] mpImplPolyPolygon->mpPolyAry;
220 19 : mpImplPolyPolygon->mpPolyAry = NULL;
221 19 : mpImplPolyPolygon->mnCount = 0;
222 19 : mpImplPolyPolygon->mnSize = mpImplPolyPolygon->mnResize;
223 : }
224 : }
225 239 : }
226 :
227 590 : void PolyPolygon::Optimize( PolyOptimizeFlags nOptimizeFlags, const PolyOptimizeData* pData )
228 : {
229 590 : if(bool(nOptimizeFlags) && Count())
230 : {
231 : // #115630# ImplDrawHatch does not work with beziers included in the polypolygon, take care of that
232 590 : bool bIsCurve(false);
233 :
234 1180 : for(sal_uInt16 a(0); !bIsCurve && a < Count(); a++)
235 : {
236 590 : if((*this)[a].HasFlags())
237 : {
238 0 : bIsCurve = true;
239 : }
240 : }
241 :
242 590 : if(bIsCurve)
243 : {
244 : OSL_ENSURE(false, "Optimize does *not* support curves, falling back to AdaptiveSubdivide()...");
245 0 : tools::PolyPolygon aPolyPoly;
246 :
247 0 : AdaptiveSubdivide(aPolyPoly);
248 0 : aPolyPoly.Optimize(nOptimizeFlags, pData);
249 0 : *this = aPolyPoly;
250 : }
251 : else
252 : {
253 : double fArea;
254 590 : const bool bEdges = ( nOptimizeFlags & PolyOptimizeFlags::EDGES ) == PolyOptimizeFlags::EDGES;
255 590 : sal_uInt16 nPercent = 0;
256 :
257 590 : if( bEdges )
258 : {
259 0 : const Rectangle aBound( GetBoundRect() );
260 :
261 0 : fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
262 0 : nPercent = pData ? pData->GetPercentValue() : 50;
263 0 : nOptimizeFlags &= ~PolyOptimizeFlags::EDGES;
264 : }
265 :
266 : // watch for ref counter
267 590 : if( mpImplPolyPolygon->mnRefCount > 1 )
268 : {
269 0 : mpImplPolyPolygon->mnRefCount--;
270 0 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
271 : }
272 :
273 : // Optimize polygons
274 1180 : for( sal_uInt16 i = 0, nPolyCount = mpImplPolyPolygon->mnCount; i < nPolyCount; i++ )
275 : {
276 590 : if( bEdges )
277 : {
278 0 : mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( PolyOptimizeFlags::NO_SAME );
279 0 : Polygon::ImplReduceEdges( *( mpImplPolyPolygon->mpPolyAry[ i ] ), fArea, nPercent );
280 : }
281 :
282 590 : if( bool(nOptimizeFlags) )
283 590 : mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( nOptimizeFlags, pData );
284 : }
285 : }
286 : }
287 590 : }
288 :
289 160 : void PolyPolygon::AdaptiveSubdivide( tools::PolyPolygon& rResult, const double d ) const
290 : {
291 160 : rResult.Clear();
292 :
293 160 : Polygon aPolygon;
294 :
295 536 : for( sal_uInt16 i = 0; i < mpImplPolyPolygon->mnCount; i++ )
296 : {
297 376 : mpImplPolyPolygon->mpPolyAry[ i ]->AdaptiveSubdivide( aPolygon, d );
298 376 : rResult.Insert( aPolygon );
299 160 : }
300 160 : }
301 :
302 2852 : tools::PolyPolygon PolyPolygon::SubdivideBezier( const tools::PolyPolygon& rPolyPoly )
303 : {
304 2852 : sal_uInt16 i, nPolys = rPolyPoly.Count();
305 2852 : tools::PolyPolygon aPolyPoly( nPolys );
306 10956 : for( i=0; i<nPolys; ++i )
307 8104 : aPolyPoly.Insert( Polygon::SubdivideBezier( rPolyPoly.GetObject(i) ) );
308 :
309 2852 : return aPolyPoly;
310 : }
311 :
312 :
313 0 : void PolyPolygon::GetIntersection( const tools::PolyPolygon& rPolyPoly, tools::PolyPolygon& rResult ) const
314 : {
315 0 : ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_INT );
316 0 : }
317 :
318 0 : void PolyPolygon::GetUnion( const tools::PolyPolygon& rPolyPoly, tools::PolyPolygon& rResult ) const
319 : {
320 0 : ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_UNION );
321 0 : }
322 :
323 0 : void PolyPolygon::ImplDoOperation( const tools::PolyPolygon& rPolyPoly, tools::PolyPolygon& rResult, sal_uIntPtr nOperation ) const
324 : {
325 : // Convert to B2DPolyPolygon, temporarily. It might be
326 : // advantageous in the future, to have a tools::PolyPolygon adaptor that
327 : // just simulates a B2DPolyPolygon here...
328 0 : basegfx::B2DPolyPolygon aMergePolyPolygonA( getB2DPolyPolygon() );
329 0 : basegfx::B2DPolyPolygon aMergePolyPolygonB( rPolyPoly.getB2DPolyPolygon() );
330 :
331 : // normalize the two polypolygons before. Force properly oriented
332 : // polygons.
333 0 : aMergePolyPolygonA = basegfx::tools::prepareForPolygonOperation( aMergePolyPolygonA );
334 0 : aMergePolyPolygonB = basegfx::tools::prepareForPolygonOperation( aMergePolyPolygonB );
335 :
336 0 : switch( nOperation )
337 : {
338 : // All code extracted from svx/source/svdraw/svedtv2.cxx
339 :
340 : case POLY_CLIP_UNION:
341 : {
342 : // merge A and B (OR)
343 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB);
344 0 : break;
345 : }
346 :
347 : case POLY_CLIP_DIFF:
348 : {
349 : // subtract B from A (DIFF)
350 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB);
351 0 : break;
352 : }
353 :
354 : case POLY_CLIP_XOR:
355 : {
356 : // compute XOR between poly A and B
357 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationXor(aMergePolyPolygonA, aMergePolyPolygonB);
358 0 : break;
359 : }
360 :
361 : default:
362 : case POLY_CLIP_INT:
363 : {
364 : // cut poly 1 against polys 2..n (AND)
365 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB);
366 0 : break;
367 : }
368 : }
369 :
370 0 : rResult = tools::PolyPolygon( aMergePolyPolygonA );
371 0 : }
372 :
373 1002661 : sal_uInt16 PolyPolygon::Count() const
374 : {
375 1002661 : return mpImplPolyPolygon->mnCount;
376 : }
377 :
378 32275 : void PolyPolygon::Move( long nHorzMove, long nVertMove )
379 : {
380 : // Required for DrawEngine
381 32275 : if( nHorzMove || nVertMove )
382 : {
383 32024 : if ( mpImplPolyPolygon->mnRefCount > 1 )
384 : {
385 31152 : mpImplPolyPolygon->mnRefCount--;
386 31152 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
387 : }
388 :
389 : // move points
390 32024 : sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
391 65351 : for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
392 33327 : mpImplPolyPolygon->mpPolyAry[i]->Move( nHorzMove, nVertMove );
393 : }
394 32275 : }
395 :
396 0 : void PolyPolygon::Translate( const Point& rTrans )
397 : {
398 0 : if( mpImplPolyPolygon->mnRefCount > 1 )
399 : {
400 0 : mpImplPolyPolygon->mnRefCount--;
401 0 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
402 : }
403 :
404 : // move points
405 0 : for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
406 0 : mpImplPolyPolygon->mpPolyAry[ i ]->Translate( rTrans );
407 0 : }
408 :
409 848 : void PolyPolygon::Scale( double fScaleX, double fScaleY )
410 : {
411 848 : if( mpImplPolyPolygon->mnRefCount > 1 )
412 : {
413 40 : mpImplPolyPolygon->mnRefCount--;
414 40 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
415 : }
416 :
417 : // Move points
418 888 : for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
419 40 : mpImplPolyPolygon->mpPolyAry[ i ]->Scale( fScaleX, fScaleY );
420 848 : }
421 :
422 0 : void PolyPolygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
423 : {
424 0 : nAngle10 %= 3600;
425 :
426 0 : if( nAngle10 )
427 : {
428 0 : const double fAngle = F_PI1800 * nAngle10;
429 0 : Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
430 : }
431 0 : }
432 :
433 200 : void PolyPolygon::Rotate( const Point& rCenter, double fSin, double fCos )
434 : {
435 200 : if( mpImplPolyPolygon->mnRefCount > 1 )
436 : {
437 0 : mpImplPolyPolygon->mnRefCount--;
438 0 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
439 : }
440 :
441 : // move points
442 501 : for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
443 301 : mpImplPolyPolygon->mpPolyAry[ i ]->Rotate( rCenter, fSin, fCos );
444 200 : }
445 :
446 7 : void PolyPolygon::Clip( const Rectangle& rRect )
447 : {
448 7 : sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
449 : sal_uInt16 i;
450 :
451 7 : if ( !nPolyCount )
452 7 : return;
453 :
454 7 : if ( mpImplPolyPolygon->mnRefCount > 1 )
455 : {
456 1 : mpImplPolyPolygon->mnRefCount--;
457 1 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
458 : }
459 :
460 : // Clip every polygon, deleting the empty ones
461 14 : for ( i = 0; i < nPolyCount; i++ )
462 7 : mpImplPolyPolygon->mpPolyAry[i]->Clip( rRect );
463 21 : while ( nPolyCount )
464 : {
465 7 : if ( GetObject( nPolyCount-1 ).GetSize() <= 2 )
466 0 : Remove( nPolyCount-1 );
467 7 : nPolyCount--;
468 : }
469 : }
470 :
471 159954 : Rectangle PolyPolygon::GetBoundRect() const
472 : {
473 159954 : long nXMin=0, nXMax=0, nYMin=0, nYMax=0;
474 159954 : bool bFirst = true;
475 159954 : sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
476 :
477 322686 : for ( sal_uInt16 n = 0; n < nPolyCount; n++ )
478 : {
479 162732 : const Polygon* pPoly = mpImplPolyPolygon->mpPolyAry[n];
480 162732 : const Point* pAry = pPoly->GetConstPointAry();
481 162732 : sal_uInt16 nPointCount = pPoly->GetSize();
482 :
483 1109406 : for ( sal_uInt16 i = 0; i < nPointCount; i++ )
484 : {
485 946674 : const Point* pPt = &pAry[ i ];
486 :
487 946674 : if ( bFirst )
488 : {
489 159954 : nXMin = nXMax = pPt->X();
490 159954 : nYMin = nYMax = pPt->Y();
491 159954 : bFirst = false;
492 : }
493 : else
494 : {
495 786720 : if ( pPt->X() < nXMin )
496 17518 : nXMin = pPt->X();
497 786720 : if ( pPt->X() > nXMax )
498 170372 : nXMax = pPt->X();
499 786720 : if ( pPt->Y() < nYMin )
500 13159 : nYMin = pPt->Y();
501 786720 : if ( pPt->Y() > nYMax )
502 171158 : nYMax = pPt->Y();
503 : }
504 : }
505 : }
506 :
507 159954 : if ( !bFirst )
508 159954 : return Rectangle( nXMin, nYMin, nXMax, nYMax );
509 : else
510 0 : return Rectangle();
511 : }
512 :
513 218483 : Polygon& PolyPolygon::operator[]( sal_uInt16 nPos )
514 : {
515 : assert(nPos < Count() && "PolyPolygon::[](): nPos >= nSize");
516 :
517 218483 : if ( mpImplPolyPolygon->mnRefCount > 1 )
518 : {
519 204074 : mpImplPolyPolygon->mnRefCount--;
520 204074 : mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
521 : }
522 :
523 218483 : return *(mpImplPolyPolygon->mpPolyAry[nPos]);
524 : }
525 :
526 8871 : PolyPolygon& PolyPolygon::operator=( const tools::PolyPolygon& rPolyPoly )
527 : {
528 8871 : if (this == &rPolyPoly)
529 0 : return *this;
530 :
531 : DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
532 :
533 8871 : rPolyPoly.mpImplPolyPolygon->mnRefCount++;
534 :
535 8871 : if ( mpImplPolyPolygon->mnRefCount > 1 )
536 808 : mpImplPolyPolygon->mnRefCount--;
537 : else
538 8063 : delete mpImplPolyPolygon;
539 :
540 8871 : mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
541 8871 : return *this;
542 : }
543 :
544 0 : bool PolyPolygon::operator==( const tools::PolyPolygon& rPolyPoly ) const
545 : {
546 0 : if ( rPolyPoly.mpImplPolyPolygon == mpImplPolyPolygon )
547 0 : return true;
548 : else
549 0 : return false;
550 : }
551 :
552 0 : bool PolyPolygon::IsEqual( const tools::PolyPolygon& rPolyPoly ) const
553 : {
554 0 : bool bIsEqual = true;
555 0 : if ( Count() != rPolyPoly.Count() )
556 0 : bIsEqual = false;
557 : else
558 : {
559 : sal_uInt16 i;
560 0 : for ( i = 0; i < Count(); i++ )
561 : {
562 0 : if (!GetObject( i ).IsEqual( rPolyPoly.GetObject( i ) ) )
563 : {
564 0 : bIsEqual = false;
565 0 : break;
566 : }
567 : }
568 : }
569 0 : return bIsEqual;
570 : }
571 :
572 521 : SvStream& ReadPolyPolygon( SvStream& rIStream, tools::PolyPolygon& rPolyPoly )
573 : {
574 : DBG_ASSERTWARNING( rIStream.GetVersion(), "PolyPolygon::>> - Solar-Version not set on rIStream" );
575 :
576 : Polygon* pPoly;
577 521 : sal_uInt16 nPolyCount(0);
578 :
579 : // Read number of polygons
580 521 : rIStream.ReadUInt16( nPolyCount );
581 :
582 521 : const size_t nMinRecordSize = sizeof(sal_uInt16);
583 521 : const size_t nMaxRecords = rIStream.remainingSize() / nMinRecordSize;
584 521 : if (nPolyCount > nMaxRecords)
585 : {
586 : SAL_WARN("tools", "Parsing error: " << nMaxRecords <<
587 : " max possible entries, but " << nPolyCount << " claimed, truncating");
588 0 : nPolyCount = nMaxRecords;
589 : }
590 :
591 521 : if( nPolyCount )
592 : {
593 521 : if ( rPolyPoly.mpImplPolyPolygon->mnRefCount > 1 )
594 0 : rPolyPoly.mpImplPolyPolygon->mnRefCount--;
595 : else
596 521 : delete rPolyPoly.mpImplPolyPolygon;
597 :
598 521 : rPolyPoly.mpImplPolyPolygon = new ImplPolyPolygon( nPolyCount );
599 :
600 1612 : for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
601 : {
602 1091 : pPoly = new Polygon;
603 1091 : ReadPolygon( rIStream, *pPoly );
604 1091 : rPolyPoly.mpImplPolyPolygon->mpPolyAry[i] = pPoly;
605 : }
606 : }
607 : else
608 0 : rPolyPoly = tools::PolyPolygon();
609 :
610 521 : return rIStream;
611 : }
612 :
613 135 : SvStream& WritePolyPolygon( SvStream& rOStream, const tools::PolyPolygon& rPolyPoly )
614 : {
615 : DBG_ASSERTWARNING( rOStream.GetVersion(), "PolyPolygon::<< - Solar-Version not set on rOStream" );
616 :
617 : // Write number of polygons
618 135 : sal_uInt16 nPolyCount = rPolyPoly.mpImplPolyPolygon->mnCount;
619 135 : rOStream.WriteUInt16( nPolyCount );
620 :
621 : // output polygons
622 482 : for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
623 347 : WritePolygon( rOStream, *(rPolyPoly.mpImplPolyPolygon->mpPolyAry[i]) );
624 :
625 135 : return rOStream;
626 : }
627 :
628 2872 : void PolyPolygon::Read( SvStream& rIStream )
629 : {
630 2872 : VersionCompat aCompat( rIStream, StreamMode::READ );
631 :
632 : DBG_ASSERTWARNING( rIStream.GetVersion(), "PolyPolygon::>> - Solar-Version not set on rIStream" );
633 :
634 : Polygon* pPoly;
635 2872 : sal_uInt16 nPolyCount(0);
636 :
637 : // Read number of polygons
638 2872 : rIStream.ReadUInt16( nPolyCount );
639 :
640 2872 : const size_t nMinRecordSize = sizeof(sal_uInt16);
641 2872 : const size_t nMaxRecords = rIStream.remainingSize() / nMinRecordSize;
642 2872 : if (nPolyCount > nMaxRecords)
643 : {
644 : SAL_WARN("tools", "Parsing error: " << nMaxRecords <<
645 : " max possible entries, but " << nPolyCount << " claimed, truncating");
646 0 : nPolyCount = nMaxRecords;
647 : }
648 :
649 2872 : if( nPolyCount )
650 : {
651 144 : if ( mpImplPolyPolygon->mnRefCount > 1 )
652 0 : mpImplPolyPolygon->mnRefCount--;
653 : else
654 144 : delete mpImplPolyPolygon;
655 :
656 144 : mpImplPolyPolygon = new ImplPolyPolygon( nPolyCount );
657 :
658 446 : for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
659 : {
660 302 : pPoly = new Polygon;
661 302 : pPoly->ImplRead( rIStream );
662 302 : mpImplPolyPolygon->mpPolyAry[i] = pPoly;
663 : }
664 : }
665 : else
666 2728 : *this = tools::PolyPolygon();
667 2872 : }
668 :
669 6882 : void PolyPolygon::Write( SvStream& rOStream ) const
670 : {
671 6882 : VersionCompat aCompat( rOStream, StreamMode::WRITE, 1 );
672 :
673 : DBG_ASSERTWARNING( rOStream.GetVersion(), "PolyPolygon::<< - Solar-Version not set on rOStream" );
674 :
675 : // Write number of polygons
676 6882 : sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
677 6882 : rOStream.WriteUInt16( nPolyCount );
678 :
679 : // Output polygons
680 7491 : for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
681 7491 : mpImplPolyPolygon->mpPolyAry[i]->ImplWrite( rOStream );
682 6882 : }
683 :
684 : // convert to basegfx::B2DPolyPolygon and return
685 4673 : basegfx::B2DPolyPolygon PolyPolygon::getB2DPolyPolygon() const
686 : {
687 4673 : basegfx::B2DPolyPolygon aRetval;
688 :
689 11873 : for(sal_uInt16 a(0); a < mpImplPolyPolygon->mnCount; a++)
690 : {
691 7200 : Polygon* pCandidate = mpImplPolyPolygon->mpPolyAry[a];
692 7200 : aRetval.append(pCandidate->getB2DPolygon());
693 : }
694 :
695 4673 : return aRetval;
696 : }
697 :
698 : // constructor to convert from basegfx::B2DPolyPolygon
699 56286 : PolyPolygon::PolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon)
700 : {
701 56286 : const sal_uInt16 nCount(sal_uInt16(rPolyPolygon.count()));
702 : DBG_ASSERT(sal_uInt32(nCount) == rPolyPolygon.count(),
703 : "PolyPolygon::PolyPolygon: Too many sub-polygons in given basegfx::B2DPolyPolygon (!)");
704 :
705 56286 : if ( nCount )
706 : {
707 52425 : mpImplPolyPolygon = new ImplPolyPolygon( nCount );
708 :
709 114240 : for(sal_uInt16 a(0); a < nCount; a++)
710 : {
711 61815 : basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(sal_uInt32(a)));
712 61815 : mpImplPolyPolygon->mpPolyAry[a] = new Polygon( aCandidate );
713 61815 : }
714 : }
715 : else
716 : {
717 3861 : mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
718 : }
719 56286 : }
720 :
721 : } /* namespace tools */
722 :
723 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|