Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/basegfx/source/polygon/b2dpolypolygon.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 <sal/config.h>
21
22
#include <cassert>
23
#include <utility>
24
25
#include <basegfx/polygon/b2dpolypolygon.hxx>
26
#include <basegfx/polygon/b2dpolygon.hxx>
27
#include <basegfx/matrix/b2dhommatrix.hxx>
28
#include <basegfx/utils/systemdependentdata.hxx>
29
30
namespace basegfx
31
{
32
33
class ImplB2DPolyPolygon
34
{
35
    basegfx::B2DPolygonVector                               maPolygons;
36
    // we do not want to 'modify' the ImplB2DPolyPolygon,
37
    // but add buffered data that is valid for all referencing instances
38
    mutable std::unique_ptr<basegfx::SystemDependentDataHolder> mpSystemDependentDataHolder;
39
40
public:
41
    ImplB2DPolyPolygon()
42
4.00M
    {
43
4.00M
    }
44
45
    explicit ImplB2DPolyPolygon(ImplB2DPolyPolygon&& rSource) noexcept
46
6.51M
        : maPolygons(std::move(rSource.maPolygons))
47
6.51M
    {
48
6.51M
    }
49
50
    explicit ImplB2DPolyPolygon(const ImplB2DPolyPolygon& rSource)
51
278k
        : maPolygons(rSource.maPolygons)
52
278k
    {
53
278k
    }
54
55
    explicit ImplB2DPolyPolygon(const basegfx::B2DPolygon& rToBeCopied)
56
6.51M
    :   maPolygons(1,rToBeCopied)
57
6.51M
    {
58
6.51M
    }
59
60
    ImplB2DPolyPolygon& operator=(const ImplB2DPolyPolygon& rSource)
61
66.5k
    {
62
66.5k
        if (this != &rSource)
63
66.5k
        {
64
66.5k
            maPolygons = rSource.maPolygons;
65
66.5k
            mpSystemDependentDataHolder.reset();
66
66.5k
        }
67
68
66.5k
        return *this;
69
66.5k
    }
70
71
    void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr& rData) const
72
0
    {
73
0
        if(!mpSystemDependentDataHolder)
74
0
        {
75
0
            mpSystemDependentDataHolder.reset(new basegfx::SystemDependentDataHolder());
76
0
        }
77
78
0
        mpSystemDependentDataHolder->addOrReplaceSystemDependentData(rData);
79
0
    }
80
81
    basegfx::SystemDependentData_SharedPtr getSystemDependentData(SDD_Type aType) const
82
3.61M
    {
83
3.61M
        if(!mpSystemDependentDataHolder)
84
3.61M
        {
85
3.61M
            return basegfx::SystemDependentData_SharedPtr();
86
3.61M
        }
87
88
0
        return mpSystemDependentDataHolder->getSystemDependentData(aType);
89
3.61M
    }
90
91
    bool operator==(const ImplB2DPolyPolygon& rPolygonList) const
92
211k
    {
93
211k
        return maPolygons == rPolygonList.maPolygons;
94
211k
    }
95
96
    const basegfx::B2DPolygon& getB2DPolygon(sal_uInt32 nIndex) const
97
38.5M
    {
98
38.5M
        assert(nIndex < maPolygons.size());
99
38.5M
        return maPolygons[nIndex];
100
38.5M
    }
101
102
    void setB2DPolygon(sal_uInt32 nIndex, const basegfx::B2DPolygon& rPolygon)
103
29.1k
    {
104
29.1k
        assert(nIndex < maPolygons.size());
105
29.1k
        maPolygons[nIndex] = rPolygon;
106
29.1k
    }
107
108
    void insert(sal_uInt32 nIndex, const basegfx::B2DPolygon& rPolygon, sal_uInt32 nCount)
109
4.79M
    {
110
4.79M
        assert(nCount > 0);
111
4.79M
        assert(nIndex <= maPolygons.size());
112
        // add nCount copies of rPolygon
113
4.79M
        maPolygons.insert(maPolygons.begin() + nIndex, nCount, rPolygon);
114
4.79M
    }
115
116
    void append(const basegfx::B2DPolygon& rPolygon, sal_uInt32 nCount)
117
4.79M
    {
118
4.79M
        insert(maPolygons.size(), rPolygon, nCount);
119
4.79M
    }
120
121
    void reserve(sal_uInt32 nCount)
122
1.38k
    {
123
1.38k
        maPolygons.reserve(nCount);
124
1.38k
    }
125
126
    void insert(sal_uInt32 nIndex, const basegfx::B2DPolyPolygon& rPolyPolygon)
127
26.9k
    {
128
26.9k
        assert(nIndex <= maPolygons.size());
129
        // add nCount polygons from rPolyPolygon
130
26.9k
        maPolygons.insert(maPolygons.begin() + nIndex, rPolyPolygon.begin(), rPolyPolygon.end());
131
26.9k
    }
132
133
    void append(const basegfx::B2DPolyPolygon& rPolyPolygon)
134
26.9k
    {
135
26.9k
        insert(maPolygons.size(), rPolyPolygon);
136
26.9k
    }
137
138
    void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
139
0
    {
140
0
        assert(nCount > 0);
141
0
        assert(nIndex + nCount <= maPolygons.size());
142
        // remove polygon data
143
0
        auto aStart(maPolygons.begin() + nIndex);
144
0
        auto aEnd(aStart + nCount);
145
146
0
        maPolygons.erase(aStart, aEnd);
147
0
    }
148
149
    sal_uInt32 count() const
150
50.4M
    {
151
50.4M
        return maPolygons.size();
152
50.4M
    }
153
154
    void setClosed(bool bNew)
155
45.3k
    {
156
45.3k
        for(basegfx::B2DPolygon & rPolygon : maPolygons)
157
58.8k
        {
158
58.8k
            rPolygon.setClosed(bNew);
159
58.8k
        }
160
45.3k
    }
161
162
    void flip()
163
0
    {
164
0
        for (auto& aPolygon : maPolygons)
165
0
            aPolygon.flip();
166
0
    }
167
168
    void removeDoublePoints()
169
2.39k
    {
170
2.39k
        for (auto& aPolygon : maPolygons)
171
56.3k
            aPolygon.removeDoublePoints();
172
2.39k
    }
173
174
    void transform(const basegfx::B2DHomMatrix& rMatrix)
175
289k
    {
176
289k
        for (auto& aPolygon : maPolygons)
177
312k
            aPolygon.transform(rMatrix);
178
289k
    }
179
180
    void translate(double fTranslateX, double fTranslateY)
181
50.4k
    {
182
50.4k
        for (auto& aPolygon : maPolygons)
183
63.1k
            aPolygon.translate(fTranslateX, fTranslateY);
184
50.4k
    }
185
186
    void makeUnique()
187
0
    {
188
0
        for (auto& aPolygon : maPolygons)
189
0
            aPolygon.makeUnique();
190
0
    }
191
192
    const basegfx::B2DPolygon* begin() const
193
4.07M
    {
194
4.07M
        if (maPolygons.empty())
195
633
            return nullptr;
196
4.07M
        else
197
4.07M
            return maPolygons.data();
198
4.07M
    }
199
200
    const basegfx::B2DPolygon* end() const
201
4.07M
    {
202
4.07M
        if (maPolygons.empty())
203
633
            return nullptr;
204
4.07M
        else
205
4.07M
            return maPolygons.data() + maPolygons.size();
206
4.07M
    }
207
208
    basegfx::B2DPolygon* begin()
209
796k
    {
210
796k
        if (maPolygons.empty())
211
0
            return nullptr;
212
796k
        else
213
796k
            return maPolygons.data();
214
796k
    }
215
216
    basegfx::B2DPolygon* end()
217
796k
    {
218
796k
        if (maPolygons.empty())
219
0
            return nullptr;
220
796k
        else
221
796k
            return maPolygons.data() + maPolygons.size();
222
796k
    }
223
};
224
225
3.93M
    B2DPolyPolygon::B2DPolyPolygon() = default;
226
227
3.32M
    B2DPolyPolygon::B2DPolyPolygon(const B2DPolyPolygon&) = default;
228
229
1.20M
    B2DPolyPolygon::B2DPolyPolygon(B2DPolyPolygon&&) = default;
230
231
    B2DPolyPolygon::B2DPolyPolygon(const B2DPolygon& rPolygon) :
232
6.51M
        mpPolyPolygon( ImplB2DPolyPolygon(rPolygon) )
233
6.51M
    {
234
6.51M
    }
235
236
14.9M
    B2DPolyPolygon::~B2DPolyPolygon() = default;
237
238
755k
    B2DPolyPolygon& B2DPolyPolygon::operator=(const B2DPolyPolygon&) = default;
239
240
954k
    B2DPolyPolygon& B2DPolyPolygon::operator=(B2DPolyPolygon&&) = default;
241
242
    void B2DPolyPolygon::makeUnique()
243
0
    {
244
0
        mpPolyPolygon->makeUnique(); // non-const cow_wrapper::operator-> calls make_unique
245
0
    }
246
247
    bool B2DPolyPolygon::operator==(const B2DPolyPolygon& rPolyPolygon) const
248
277k
    {
249
277k
        if(mpPolyPolygon.same_object(rPolyPolygon.mpPolyPolygon))
250
65.1k
            return true;
251
252
211k
        return ((*mpPolyPolygon) == (*rPolyPolygon.mpPolyPolygon));
253
277k
    }
254
255
    sal_uInt32 B2DPolyPolygon::count() const
256
50.4M
    {
257
50.4M
        return mpPolyPolygon->count();
258
50.4M
    }
259
260
    B2DPolygon const & B2DPolyPolygon::getB2DPolygon(sal_uInt32 nIndex) const
261
38.5M
    {
262
38.5M
        return mpPolyPolygon->getB2DPolygon(nIndex);
263
38.5M
    }
264
265
    void B2DPolyPolygon::setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon& rPolygon)
266
29.1k
    {
267
29.1k
        if(getB2DPolygon(nIndex) != rPolygon)
268
29.1k
            mpPolyPolygon->setB2DPolygon(nIndex, rPolygon);
269
29.1k
    }
270
271
    bool B2DPolyPolygon::areControlPointsUsed() const
272
812k
    {
273
1.73M
        for(sal_uInt32 a(0); a < count(); a++)
274
944k
        {
275
944k
            if(getB2DPolygon(a).areControlPointsUsed())
276
17.4k
            {
277
17.4k
                return true;
278
17.4k
            }
279
944k
        }
280
281
795k
        return false;
282
812k
    }
283
284
    void B2DPolyPolygon::insert(sal_uInt32 nIndex, const B2DPolygon& rPolygon, sal_uInt32 nCount)
285
0
    {
286
0
        if(nCount)
287
0
            mpPolyPolygon->insert(nIndex, rPolygon, nCount);
288
0
    }
289
290
    void B2DPolyPolygon::append(const B2DPolygon& rPolygon, sal_uInt32 nCount)
291
4.79M
    {
292
4.79M
        if(nCount)
293
4.79M
            mpPolyPolygon->append(rPolygon, nCount);
294
4.79M
    }
295
296
    void B2DPolyPolygon::reserve(sal_uInt32 nCount)
297
1.38k
    {
298
1.38k
        if(nCount)
299
1.38k
            mpPolyPolygon->reserve(nCount);
300
1.38k
    }
301
302
    B2DPolyPolygon B2DPolyPolygon::getDefaultAdaptiveSubdivision() const
303
0
    {
304
0
        B2DPolyPolygon aRetval;
305
0
        if (count())
306
0
        {
307
0
            ImplB2DPolyPolygon& dest = *aRetval.mpPolyPolygon;
308
0
            dest.reserve(count());
309
310
0
            for (sal_uInt32 a(0); a < count(); a++)
311
0
            {
312
0
                dest.append(getB2DPolygon(a).getDefaultAdaptiveSubdivision(), 1);
313
0
            }
314
0
        }
315
316
0
        return aRetval;
317
0
    }
318
319
    B2DRange B2DPolyPolygon::getB2DRange() const
320
15.2M
    {
321
15.2M
        B2DRange aRetval;
322
323
33.0M
        for(sal_uInt32 a(0); a < count(); a++)
324
17.8M
        {
325
17.8M
            aRetval.expand(getB2DPolygon(a).getB2DRange());
326
17.8M
        }
327
328
15.2M
        return aRetval;
329
15.2M
    }
330
331
    void B2DPolyPolygon::insert(sal_uInt32 nIndex, const B2DPolyPolygon& rPolyPolygon)
332
0
    {
333
0
        if(rPolyPolygon.count())
334
0
            mpPolyPolygon->insert(nIndex, rPolyPolygon);
335
0
    }
336
337
    void B2DPolyPolygon::append(const B2DPolyPolygon& rPolyPolygon)
338
27.8k
    {
339
27.8k
        if(rPolyPolygon.count())
340
26.9k
            mpPolyPolygon->append(rPolyPolygon);
341
27.8k
    }
342
343
    void B2DPolyPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
344
0
    {
345
0
        if(nCount)
346
0
            mpPolyPolygon->remove(nIndex, nCount);
347
0
    }
348
349
    void B2DPolyPolygon::clear()
350
66.5k
    {
351
66.5k
        *mpPolyPolygon = ImplB2DPolyPolygon();
352
66.5k
    }
353
354
    bool B2DPolyPolygon::isClosed() const
355
911k
    {
356
        // PolyPOlygon is closed when all contained Polygons are closed or
357
        // no Polygon exists.
358
2.18M
        for(sal_uInt32 a(0); a < count(); a++)
359
1.40M
        {
360
1.40M
            if(!getB2DPolygon(a).isClosed())
361
135k
                return false;
362
1.40M
        }
363
364
776k
        return true;
365
911k
    }
366
367
    void B2DPolyPolygon::setClosed(bool bNew)
368
56.6k
    {
369
56.6k
        if(bNew != isClosed())
370
45.3k
            mpPolyPolygon->setClosed(bNew);
371
56.6k
    }
372
373
    void B2DPolyPolygon::flip()
374
0
    {
375
0
        if(count())
376
0
        {
377
0
            mpPolyPolygon->flip();
378
0
        }
379
0
    }
380
381
    bool B2DPolyPolygon::hasDoublePoints() const
382
337k
    {
383
679k
        for(sal_uInt32 a(0); a < count(); a++)
384
343k
        {
385
343k
            if(getB2DPolygon(a).hasDoublePoints())
386
2.39k
                return true;
387
343k
        }
388
389
335k
        return false;
390
337k
    }
391
392
    void B2DPolyPolygon::removeDoublePoints()
393
337k
    {
394
337k
        if(hasDoublePoints())
395
2.39k
            mpPolyPolygon->removeDoublePoints();
396
337k
    }
397
398
    void B2DPolyPolygon::transform(const B2DHomMatrix& rMatrix)
399
306k
    {
400
306k
        if(count() && !rMatrix.isIdentity())
401
289k
        {
402
289k
            mpPolyPolygon->transform(rMatrix);
403
289k
        }
404
306k
    }
405
406
    void B2DPolyPolygon::translate(double fTranslateX, double fTranslateY)
407
54.4k
    {
408
54.4k
        if(count())
409
50.4k
        {
410
50.4k
            mpPolyPolygon->translate(fTranslateX, fTranslateY);
411
50.4k
        }
412
54.4k
    }
413
414
    const B2DPolygon* B2DPolyPolygon::begin() const
415
4.07M
    {
416
4.07M
        return mpPolyPolygon->begin();
417
4.07M
    }
418
419
    const B2DPolygon* B2DPolyPolygon::end() const
420
4.07M
    {
421
4.07M
        return mpPolyPolygon->end();
422
4.07M
    }
423
424
    B2DPolygon* B2DPolyPolygon::begin()
425
796k
    {
426
796k
        return mpPolyPolygon->begin();
427
796k
    }
428
429
    B2DPolygon* B2DPolyPolygon::end()
430
796k
    {
431
796k
        return mpPolyPolygon->end();
432
796k
    }
433
434
    void B2DPolyPolygon::addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const
435
0
    {
436
0
        mpPolyPolygon->addOrReplaceSystemDependentData(rData);
437
0
    }
438
439
    SystemDependentData_SharedPtr B2DPolyPolygon::getSystemDependantDataInternal(SDD_Type aType) const
440
3.61M
    {
441
3.61M
        return mpPolyPolygon->getSystemDependentData(aType);
442
3.61M
    }
443
444
} // end of namespace basegfx
445
446
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */