Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/basegfx/source/tools/unopolypolygon.cxx
Line
Count
Source
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 <com/sun/star/lang/IllegalArgumentException.hpp>
21
22
#include <basegfx/range/b2drange.hxx>
23
#include <basegfx/point/b2dpoint.hxx>
24
#include <basegfx/utils/canvastools.hxx>
25
#include <basegfx/polygon/b2dpolygon.hxx>
26
#include <basegfx/polygon/b2dpolypolygontools.hxx>
27
#include <basegfx/utils/unopolypolygon.hxx>
28
#include <cppuhelper/supportsservice.hxx>
29
#include <utility>
30
31
using namespace ::com::sun::star;
32
33
namespace basegfx::unotools
34
{
35
    UnoPolyPolygon::UnoPolyPolygon( B2DPolyPolygon aPolyPoly ) :
36
0
        maPolyPoly(std::move( aPolyPoly )),
37
0
        meFillRule( rendering::FillRule_EVEN_ODD )
38
0
    {
39
0
    }
Unexecuted instantiation: basegfx::unotools::UnoPolyPolygon::UnoPolyPolygon(basegfx::B2DPolyPolygon)
Unexecuted instantiation: basegfx::unotools::UnoPolyPolygon::UnoPolyPolygon(basegfx::B2DPolyPolygon)
40
41
    void SAL_CALL UnoPolyPolygon::addPolyPolygon(
42
        const geometry::RealPoint2D&                        position,
43
        const uno::Reference< rendering::XPolyPolygon2D >&  polyPolygon )
44
0
    {
45
0
        std::unique_lock const guard( m_aMutex );
46
0
        modifying();
47
48
        // TODO(F1): Correctly fulfill the UNO API
49
        // specification. This will probably result in a vector of
50
        // poly-polygons to be stored in this object.
51
52
0
        const sal_Int32 nPolys( polyPolygon->getNumberOfPolygons() );
53
54
0
        if( !polyPolygon.is() || !nPolys )
55
0
        {
56
            // invalid or empty polygon - nothing to do.
57
0
            return;
58
0
        }
59
60
0
        B2DPolyPolygon        aSrcPoly;
61
0
        const UnoPolyPolygon* pSrc( dynamic_cast< UnoPolyPolygon* >(polyPolygon.get()) );
62
63
        // try to extract polygon data from interface. First,
64
        // check whether it's the same implementation object,
65
        // which we can tunnel then.
66
0
        if( pSrc )
67
0
        {
68
0
            aSrcPoly = pSrc->getPolyPolygon();
69
0
        }
70
0
        else
71
0
        {
72
            // not a known implementation object - try data source
73
            // interfaces
74
0
            uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly(
75
0
                polyPolygon,
76
0
                uno::UNO_QUERY );
77
78
0
            if( xBezierPoly.is() )
79
0
            {
80
0
                aSrcPoly = unotools::polyPolygonFromBezier2DSequenceSequence(
81
0
                    xBezierPoly->getBezierSegments( 0,
82
0
                                                    nPolys,
83
0
                                                    0,
84
0
                                                    -1 ) );
85
0
            }
86
0
            else
87
0
            {
88
0
                uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly(
89
0
                    polyPolygon,
90
0
                    uno::UNO_QUERY );
91
92
                // no implementation class and no data provider
93
                // found - contract violation.
94
0
                if( !xLinePoly.is() )
95
0
                    throw lang::IllegalArgumentException(
96
0
                        u"UnoPolyPolygon::addPolyPolygon(): Invalid input "
97
0
                        "poly-polygon, cannot retrieve vertex data"_ustr,
98
0
                        getXWeak(), 1);
99
100
0
                aSrcPoly = unotools::polyPolygonFromPoint2DSequenceSequence(
101
0
                    xLinePoly->getPoints( 0,
102
0
                                          nPolys,
103
0
                                          0,
104
0
                                          -1 ) );
105
0
            }
106
0
        }
107
108
0
        const B2DRange  aBounds( aSrcPoly.getB2DRange() );
109
0
        const B2DVector     aOffset( unotools::b2DPointFromRealPoint2D( position ) -
110
0
                                             aBounds.getMinimum() );
111
112
0
        if( !aOffset.equalZero() )
113
0
        {
114
0
            aSrcPoly.translate( aOffset );
115
0
        }
116
117
0
        maPolyPoly.append( aSrcPoly );
118
0
    }
119
120
    sal_Int32 SAL_CALL UnoPolyPolygon::getNumberOfPolygons()
121
0
    {
122
0
        std::unique_lock const guard( m_aMutex );
123
0
        return maPolyPoly.count();
124
0
    }
125
126
    sal_Int32 SAL_CALL UnoPolyPolygon::getNumberOfPolygonPoints(
127
        sal_Int32 polygon )
128
0
    {
129
0
        std::unique_lock const guard( m_aMutex );
130
0
        checkIndex( polygon );
131
132
0
        return maPolyPoly.getB2DPolygon(polygon).count();
133
0
    }
134
135
    rendering::FillRule SAL_CALL UnoPolyPolygon::getFillRule()
136
0
    {
137
0
        std::unique_lock const guard( m_aMutex );
138
0
        return meFillRule;
139
0
    }
140
141
    void SAL_CALL UnoPolyPolygon::setFillRule(
142
        rendering::FillRule fillRule )
143
0
    {
144
0
        std::unique_lock const guard( m_aMutex );
145
0
        modifying();
146
147
0
        meFillRule = fillRule;
148
0
    }
149
150
    sal_Bool SAL_CALL UnoPolyPolygon::isClosed(
151
        sal_Int32 index )
152
0
    {
153
0
        std::unique_lock const guard( m_aMutex );
154
0
        checkIndex( index );
155
156
0
        return maPolyPoly.getB2DPolygon(index).isClosed();
157
0
    }
158
159
    void SAL_CALL UnoPolyPolygon::setClosed(
160
        sal_Int32 index,
161
        sal_Bool closedState )
162
0
    {
163
0
        std::unique_lock const guard( m_aMutex );
164
0
        modifying();
165
166
0
        if( index == -1 )
167
0
        {
168
            // set all
169
0
            maPolyPoly.setClosed( closedState );
170
0
        }
171
0
        else
172
0
        {
173
0
            checkIndex( index );
174
175
            // fetch referenced polygon, change state
176
0
            B2DPolygon aTmp( maPolyPoly.getB2DPolygon(index) );
177
0
            aTmp.setClosed( closedState );
178
179
            // set back to container
180
0
            maPolyPoly.setB2DPolygon( index, aTmp );
181
0
        }
182
0
    }
183
184
    uno::Sequence< uno::Sequence< geometry::RealPoint2D > > SAL_CALL UnoPolyPolygon::getPoints(
185
        sal_Int32 nPolygonIndex,
186
        sal_Int32 nNumberOfPolygons,
187
        sal_Int32 nPointIndex,
188
        sal_Int32 nNumberOfPoints )
189
0
    {
190
0
        return unotools::pointSequenceSequenceFromB2DPolyPolygon(
191
0
            getSubsetPolyPolygon( nPolygonIndex,
192
0
                                  nNumberOfPolygons,
193
0
                                  nPointIndex,
194
0
                                  nNumberOfPoints ) );
195
0
    }
196
197
    void SAL_CALL UnoPolyPolygon::setPoints(
198
        const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points,
199
        sal_Int32 nPolygonIndex )
200
0
    {
201
0
        std::unique_lock const guard( m_aMutex );
202
0
        modifying();
203
204
0
        const B2DPolyPolygon aNewPolyPoly(
205
0
            unotools::polyPolygonFromPoint2DSequenceSequence( points ) );
206
207
0
        if( nPolygonIndex == -1 )
208
0
        {
209
0
            maPolyPoly = aNewPolyPoly;
210
0
        }
211
0
        else
212
0
        {
213
0
            checkIndex( nPolygonIndex );
214
215
0
            maPolyPoly.insert( nPolygonIndex, aNewPolyPoly );
216
0
        }
217
0
    }
218
219
    geometry::RealPoint2D SAL_CALL UnoPolyPolygon::getPoint(
220
        sal_Int32 nPolygonIndex,
221
        sal_Int32 nPointIndex )
222
0
    {
223
0
        std::unique_lock const guard( m_aMutex );
224
0
        checkIndex( nPolygonIndex );
225
226
0
        const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) );
227
228
0
        if( nPointIndex < 0 || o3tl::make_unsigned(nPointIndex) >= rPoly.count() )
229
0
            throw lang::IndexOutOfBoundsException();
230
231
0
        return unotools::point2DFromB2DPoint( rPoly.getB2DPoint( nPointIndex ) );
232
0
    }
233
234
    void SAL_CALL UnoPolyPolygon::setPoint(
235
        const geometry::RealPoint2D& point,
236
        sal_Int32 nPolygonIndex,
237
        sal_Int32 nPointIndex )
238
0
    {
239
0
        std::unique_lock const guard( m_aMutex );
240
0
        checkIndex( nPolygonIndex );
241
0
        modifying();
242
243
0
        B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) );
244
245
0
        if( nPointIndex < 0 || o3tl::make_unsigned(nPointIndex) >= aPoly.count() )
246
0
            throw lang::IndexOutOfBoundsException();
247
248
0
        aPoly.setB2DPoint( nPointIndex,
249
0
                           unotools::b2DPointFromRealPoint2D( point ) );
250
0
        maPolyPoly.setB2DPolygon( nPolygonIndex, aPoly );
251
0
    }
252
253
    uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > SAL_CALL UnoPolyPolygon::getBezierSegments(
254
        sal_Int32 nPolygonIndex,
255
        sal_Int32 nNumberOfPolygons,
256
        sal_Int32 nPointIndex,
257
        sal_Int32 nNumberOfPoints )
258
0
    {
259
0
        return unotools::bezierSequenceSequenceFromB2DPolyPolygon(
260
0
            getSubsetPolyPolygon( nPolygonIndex,
261
0
                                  nNumberOfPolygons,
262
0
                                  nPointIndex,
263
0
                                  nNumberOfPoints ) );
264
0
    }
265
266
    void SAL_CALL UnoPolyPolygon::setBezierSegments(
267
        const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >&  points,
268
        sal_Int32                                                               nPolygonIndex )
269
0
    {
270
0
        std::unique_lock const guard( m_aMutex );
271
0
        modifying();
272
0
        const B2DPolyPolygon aNewPolyPoly(
273
0
            unotools::polyPolygonFromBezier2DSequenceSequence( points ) );
274
275
0
        if( nPolygonIndex == -1 )
276
0
        {
277
0
            maPolyPoly = aNewPolyPoly;
278
0
        }
279
0
        else
280
0
        {
281
0
            checkIndex( nPolygonIndex );
282
283
0
            maPolyPoly.insert( nPolygonIndex, aNewPolyPoly );
284
0
        }
285
0
    }
286
287
    geometry::RealBezierSegment2D SAL_CALL UnoPolyPolygon::getBezierSegment( sal_Int32 nPolygonIndex,
288
                                                                             sal_Int32 nPointIndex )
289
0
    {
290
0
        std::unique_lock const guard( m_aMutex );
291
0
        checkIndex( nPolygonIndex );
292
293
0
        const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) );
294
0
        const sal_uInt32  nPointCount(rPoly.count());
295
296
0
        if( nPointIndex < 0 || o3tl::make_unsigned(nPointIndex) >= nPointCount )
297
0
            throw lang::IndexOutOfBoundsException();
298
299
0
        const B2DPoint& rPt( rPoly.getB2DPoint( nPointIndex ) );
300
0
        const B2DPoint aCtrl0( rPoly.getNextControlPoint(nPointIndex) );
301
0
        const B2DPoint aCtrl1( rPoly.getPrevControlPoint((nPointIndex + 1) % nPointCount) );
302
303
0
        return geometry::RealBezierSegment2D( rPt.getX(),
304
0
                                              rPt.getY(),
305
0
                                              aCtrl0.getX(),
306
0
                                              aCtrl0.getY(),
307
0
                                              aCtrl1.getX(),
308
0
                                              aCtrl1.getY() );
309
0
    }
310
311
    void SAL_CALL UnoPolyPolygon::setBezierSegment( const geometry::RealBezierSegment2D& segment,
312
                                                         sal_Int32                       nPolygonIndex,
313
                                                         sal_Int32                       nPointIndex )
314
0
    {
315
0
        std::unique_lock const guard( m_aMutex );
316
0
        checkIndex( nPolygonIndex );
317
0
        modifying();
318
319
0
        B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) );
320
0
        const sal_uInt32 nPointCount(aPoly.count());
321
322
0
        if( nPointIndex < 0 || o3tl::make_unsigned(nPointIndex) >= nPointCount )
323
0
            throw lang::IndexOutOfBoundsException();
324
325
0
        aPoly.setB2DPoint( nPointIndex,
326
0
                           B2DPoint( segment.Px,
327
0
                                     segment.Py ) );
328
0
        aPoly.setNextControlPoint(nPointIndex,
329
0
                                  B2DPoint(segment.C1x, segment.C1y));
330
0
        aPoly.setPrevControlPoint((nPointIndex + 1) % nPointCount,
331
0
                                  B2DPoint(segment.C2x, segment.C2y));
332
333
0
        maPolyPoly.setB2DPolygon( nPolygonIndex, aPoly );
334
0
    }
335
336
    B2DPolyPolygon UnoPolyPolygon::getSubsetPolyPolygon(
337
        sal_Int32 nPolygonIndex,
338
        sal_Int32 nNumberOfPolygons,
339
        sal_Int32 nPointIndex,
340
        sal_Int32 nNumberOfPoints ) const
341
0
    {
342
0
        std::unique_lock const guard( m_aMutex );
343
0
        checkIndex( nPolygonIndex );
344
345
0
        const sal_Int32 nPolyCount( maPolyPoly.count() );
346
347
        // check for "full polygon" case
348
0
        if( !nPolygonIndex &&
349
0
            !nPointIndex &&
350
0
            nNumberOfPolygons == nPolyCount &&
351
0
            nNumberOfPoints == -1 )
352
0
        {
353
0
            return maPolyPoly;
354
0
        }
355
356
0
        B2DPolyPolygon aSubsetPoly;
357
358
        // create temporary polygon (as an extract from maPoly,
359
        // which contains the requested subset)
360
0
        for( sal_Int32 i=nPolygonIndex; i<nNumberOfPolygons; ++i )
361
0
        {
362
0
            checkIndex(i);
363
364
0
            const B2DPolygon& rCurrPoly( maPolyPoly.getB2DPolygon(i) );
365
366
0
            sal_Int32 nFirstPoint(0);
367
0
            sal_Int32 nLastPoint(nPolyCount-1);
368
369
0
            if( nPointIndex && i==nPolygonIndex )
370
0
            {
371
                // very first polygon - respect nPointIndex, if
372
                // not zero
373
374
                // empty polygon - impossible to specify _any_
375
                // legal value except 0 here!
376
0
                if( !nPolyCount)
377
0
                    throw lang::IndexOutOfBoundsException();
378
379
0
                nFirstPoint = nPointIndex;
380
0
            }
381
382
0
            if( i==nNumberOfPolygons-1 && nNumberOfPoints != -1 )
383
0
            {
384
                // very last polygon - respect nNumberOfPoints
385
386
                // empty polygon - impossible to specify _any_
387
                // legal value except -1 here!
388
0
                if( !nPolyCount )
389
0
                    throw lang::IndexOutOfBoundsException();
390
391
0
                nLastPoint = nFirstPoint+nNumberOfPoints;
392
0
            }
393
394
0
            if( !nPolyCount )
395
0
            {
396
                // empty polygon - index checks already performed
397
                // above, now simply append empty polygon
398
0
                aSubsetPoly.append( rCurrPoly );
399
0
            }
400
0
            else
401
0
            {
402
0
                if( nFirstPoint < 0 || nFirstPoint >= nPolyCount )
403
0
                    throw lang::IndexOutOfBoundsException();
404
405
0
                if( nLastPoint < 0 || nLastPoint >= nPolyCount )
406
0
                    throw lang::IndexOutOfBoundsException();
407
408
0
                B2DPolygon aTmp;
409
0
                for( sal_Int32 j=nFirstPoint; j<nLastPoint; ++j )
410
0
                    aTmp.append( rCurrPoly.getB2DPoint(j) );
411
412
0
                aSubsetPoly.append( aTmp );
413
0
            }
414
0
        }
415
416
0
        return aSubsetPoly;
417
0
    }
418
419
    OUString SAL_CALL UnoPolyPolygon::getImplementationName()
420
0
    {
421
0
        return u"gfx::internal::UnoPolyPolygon"_ustr;
422
0
    }
423
424
    sal_Bool SAL_CALL UnoPolyPolygon::supportsService( const OUString& ServiceName )
425
0
    {
426
0
        return cppu::supportsService(this, ServiceName);
427
0
    }
428
429
    uno::Sequence< OUString > SAL_CALL UnoPolyPolygon::getSupportedServiceNames()
430
0
    {
431
0
        return { u"com.sun.star.rendering.PolyPolygon2D"_ustr };
432
0
    }
433
434
    B2DPolyPolygon UnoPolyPolygon::getPolyPolygon() const
435
0
    {
436
0
        std::unique_lock const guard( m_aMutex );
437
438
0
        return maPolyPoly;
439
0
    }
440
441
}
442
443
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */